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.

3223 lines
88 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Connect.cpp
  6. * Content: DNET connection routines
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 09/01/99 mjn Created
  12. * 12/23/99 mjn Hand all NameTable update sends from Host to worker thread
  13. * 12/23/99 mjn Fixed Host and AllPlayers short-cut pointer use
  14. * 12/28/99 mjn Moved Async Op stuff to Async.h
  15. * 12/29/99 mjn Reformed DN_ASYNC_OP to use hParentOp instead of lpvUserContext
  16. * 12/29/99 mjn Turned off Instance GUID verification - TODO - turn back on !
  17. * 01/06/00 mjn Moved NameTable stuff to NameTable.h
  18. * 01/07/00 mjn Moved Misc Functions to DNMisc.h
  19. * 01/07/00 mjn DNHostVerifyConnect ensures connection to Host player only
  20. * 01/08/00 mjn Failed connection returns HRESULT and buffer from Host
  21. * 01/08/00 mjn Added group owner to NameTable
  22. * 01/08/00 mjn Changed DNERR_INVALIDHOST to DNERR_NOTHOST
  23. * 01/08/00 mjn Removed unused connection info
  24. * 01/09/00 mjn Transfer Application Description at connect
  25. * 01/10/00 mjn Fixed Application Description usage
  26. * 01/11/00 mjn Use CPackedBuffers instead of DN_ENUM_BUFFER_INFOs
  27. * 01/13/00 mjn Removed DIRECTNETOBJECT from Pack/UnpackApplicationDesc
  28. * 01/14/00 mjn Removed pvUserContext from DN_NAMETABLE_ENTRY
  29. * 01/14/00 mjn Added password to DN_APPLICATION_DESC_PACKED_INFO
  30. * 01/15/00 mjn Replaced DN_COUNT_BUFFER with CRefCountBuffer
  31. * 01/16/00 mjn Moved User callback stuff to User.h
  32. * 01/17/00 mjn Fixed ConnectToPeer function names
  33. * 01/18/00 mjn Moved Pack/UnpackNameTableInfo to NameTable.cpp
  34. * 01/24/00 mjn Replaced on-wire message pointers to offsets
  35. * 02/01/00 mjn Implement Player/Group context values
  36. * 03/23/00 mjn Set player context through Connect
  37. * 03/24/00 mjn Set player context through INDICATE_CONNECT notification
  38. * 04/03/00 mjn Verify DNET version on connect
  39. * 04/09/00 mjn Modified Connect process to use CAsyncOp
  40. * 04/16/00 mjn DNSendMessage() uses CAsyncOp
  41. * 04/18/00 mjn CConnection tracks connection status better
  42. * mjn Fixed player count problem
  43. * mjn Return connect user reply buffer
  44. * 04/19/00 mjn Fixed DNConnectToHost2 to set DirectNet object flags to CONNECTED
  45. * mjn Update NameTable operations to use DN_WORKER_JOB_SEND_NAMETABLE_OPERATION
  46. * 04/20/00 mjn Host queries for connecting players' address if not specified
  47. * 05/03/00 mjn Prevent unrequired RETURN_BUFFER message when CONNECT fails on Host player
  48. * 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer()
  49. * 05/08/00 mjn Host sets connecting player's Connection as soon as player entry created
  50. * 05/09/00 mjn Fixed New Player connection sequence to send NAMETABLE_ACK earlier
  51. * 05/23/00 mjn Added DNConnectToPeerFailed()
  52. * 06/14/00 mjn Added DNGetLocalAddress()
  53. * 06/19/00 mjn Fixed connect process to better handle ALL_ADAPTERS case
  54. * 06/22/00 mjn NameTable::UnpackNameTableInfo() returns local players DPNID
  55. * mjn Replace CConnection::MakeConnecting(),MakeConnected() with SetStatus()
  56. * 06/24/00 mjn Added DNHostDropPlayer() to handle failed existing player connects to new players
  57. * 06/25/00 mjn Added code to update lobby when DISCONNECTED
  58. * 06/26/00 mjn Indicate COULDNOTCONNECT to lobby if connect to Host fails
  59. * 06/27/00 rmt Added abstraction for COM_Co(Un)Initialize
  60. * mjn Host will attempt to determine connecting player's address if not specified in connect block
  61. * 07/05/00 mjn More robust handling of disconnecting joining players during connection process
  62. * 07/06/00 mjn More connect fixes
  63. * 07/20/00 mjn The CONNECT process was revamped - new completions, asyncop structure, messages
  64. * mjn Better error handling for shutdown in DNHostVerifyConnect()
  65. * mjn Fixed up DNHostDropPlayer() to inform NewPlayer of drop
  66. * 07/21/00 mjn Added code to handle unreachable players during connect process
  67. * 07/22/00 mjn Extract connecting player's DNET version
  68. * 07/25/00 mjn Update connect parent async op's result at end of DNConnectToHost2()
  69. * 07/27/00 mjn Fixed locking problem with CAsyncOp::MakeChild()
  70. * 07/29/00 mjn Save connection in DNConnectToHost1() on connect parent for better clean up
  71. * 07/30/00 mjn Renamed DNGetLocalAddress() to DNGetLocalDeviceAddress()
  72. * 07/31/00 mjn Added hrReason to DNTerminateSession()
  73. * mjn Added dwDestroyReason to DNHostDisconnect()
  74. * 08/02/00 mjn Removed unused code
  75. * 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  76. * 08/05/00 rmt Bug #41356 - DPLAY8: CORE: Connections refused by DPlay leak address objects
  77. * 08/05/00 mjn Added pParent to DNSendGroupMessage and DNSendMessage()
  78. * 08/06/00 mjn Added CWorkerJob
  79. * 08/08/00 mjn Mark groups created after CREATE_GROUP
  80. * 08/15/00 rmt Bug #42506 - DPLAY8: LOBBY: Automatic connection settings not being sent
  81. * 08/25/00 mjn Perform queued NameTable operations in DNConnectToHost2()
  82. * 08/28/00 mjn Only compare major version numbers in DNHostVerifyConnect()
  83. * 09/04/00 mjn Added CApplicationDesc
  84. * 09/05/00 mjn Set NameTable DPNID mask when connecting
  85. * 09/13/00 mjn Perform queued operations after creating group in DNConnectToHost2()
  86. * 09/17/00 mjn Split CNameTable.m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups
  87. * 09/26/00 mjn Removed locking from CNameTable::SetVersion() and CNameTable::GetNewVersion()
  88. * 09/27/00 mjn ACK nametable to Host after creating groups and local and host players
  89. * 10/11/00 mjn Fixed up DNAbortConnect() and use it instead of DNConnectToHostFailed()
  90. * 10/17/00 mjn Fixed clean up for unreachable players
  91. * 01/25/01 mjn Fixed 64-bit alignment problem in received messages
  92. * 02/12/01 mjn Fixed CConnection::GetEndPt() to track calling thread
  93. * 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's
  94. * 04/05/01 mjn Call DNHostDisconnect() with DPNDESTROYPLAYERREASON_NORMAL in DNHostConnect1()
  95. * 05/07/01 vpo Whistler 384350: "DPLAY8: CORE: Messages from server can be indicated before connect completes"
  96. * 05/22/01 mjn Properly set DirectNetObject as CONNECTED for successful client connect
  97. * 06/03/01 mjn Don't clean up connect parent from DirectNetObject in DNAbortConnect() (will be done in DNTerminateSession())
  98. * 06/08/01 mjn Disconnect connection in DNConnectToHostFailed()
  99. * 06/25/01 mjn Use connect address for host if missing when installing name table in DNConnectToHost2()
  100. * 07/24/01 mjn Added DPNBUILD_NOSERVER compile flag
  101. *@@END_MSINTERNAL
  102. *
  103. ***************************************************************************/
  104. #include "dncorei.h"
  105. //
  106. // Accept a connection from a NewPlayer as the Host in peer-to-peer, or as the Server in
  107. // Client-Server modes.
  108. //
  109. // The connection process is a multi part affair, requiring a bit of
  110. // synchronization between the Host and the NewPlayer.
  111. //
  112. // In the first part:
  113. // The Host waits for the NewPlayer to send player game info
  114. // The Host verifies that everything is in order
  115. // If everything is okay:
  116. // The Host assigns the NewPlayer a DNID,
  117. // Adds the NewPlayer to the Host's NameTable,
  118. // Sends the NameTable to the NewPlayer,
  119. // Sends an ADD_PLAYER message to existing players to add NewPlayer to their NameTable's
  120. // Otherwise:
  121. // Inform NewPlayer that connection process failed
  122. //
  123. // In the second part:
  124. // The Host awaits confirmation from the NewPlayer that the table was received AND installed.
  125. // The Host instructs existing players to connect to the NewPlayer
  126. //
  127. // DNHostConnect1
  128. //
  129. // Called once the connecting player has sent his player info.
  130. //
  131. // - Verify NewPlayer and application info
  132. // - Assign a DNID to NewPlayer
  133. // - Add NewPlayer to Host's NameTable
  134. // - Send Name table to NewPlayer
  135. // - Send ADD_PLAYER message to existing players
  136. //
  137. // LPVOID lpvData Player and application info
  138. // DWORD dwBufferSize Size of player and application info
  139. // HANDLE hEndPt End point handle
  140. #undef DPF_MODNAME
  141. #define DPF_MODNAME "DNHostConnect1"
  142. HRESULT DNHostConnect1(DIRECTNETOBJECT *const pdnObject,
  143. const PVOID pvBuffer,
  144. const DWORD dwBufferSize,
  145. CConnection *const pConnection)
  146. {
  147. HRESULT hResultCode;
  148. UNALIGNED WCHAR *pwszName;
  149. UNALIGNED WCHAR *pwszPassword;
  150. PVOID pvData;
  151. PVOID pvConnectData;
  152. UNALIGNED DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO *pInfo;
  153. CNameTableEntry *pNTEntry;
  154. CNameTableEntry *pAllPlayersGroup;
  155. CPackedBuffer packedBuffer;
  156. CRefCountBuffer *pRefCountBuffer;
  157. CWorkerJob *pWorkerJob;
  158. IDirectPlay8Address *pAddress;
  159. CPackedBuffer PackedBuffer;
  160. void *pvPlayerContext;
  161. BOOL bPlayerVerified;
  162. BOOL fDisconnect;
  163. HANDLE hEndPt;
  164. void *pvReplyBuffer;
  165. DWORD dwReplyBufferSize;
  166. void *pvReplyBufferContext;
  167. CCallbackThread CallbackThread;
  168. #ifdef DBG
  169. TCHAR DP8ABuffer[512] = {0};
  170. DWORD DP8ASize;
  171. #endif // DBG
  172. DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p], dwBufferSize [%ld], pConnection [0x%p]",pvBuffer,dwBufferSize,pConnection);
  173. DNASSERT(pdnObject != NULL);
  174. DNASSERT(pvBuffer != NULL);
  175. DNASSERT(pConnection != NULL);
  176. pAddress = NULL;
  177. pRefCountBuffer = NULL;
  178. pNTEntry = NULL;
  179. pAllPlayersGroup = NULL;
  180. pWorkerJob = NULL;
  181. bPlayerVerified = FALSE;
  182. pvReplyBuffer = NULL;
  183. dwReplyBufferSize = 0;
  184. pvReplyBufferContext = NULL;
  185. CallbackThread.Initialize();
  186. //
  187. // Extract player and application info
  188. //
  189. pInfo = static_cast<DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO*>(pvBuffer);
  190. if (pInfo->dwNameOffset)
  191. {
  192. pwszName = reinterpret_cast<UNALIGNED WCHAR*>(static_cast<BYTE*>(pvBuffer) + pInfo->dwNameOffset);
  193. }
  194. else
  195. {
  196. pwszName = NULL;
  197. }
  198. if (pInfo->dwPasswordOffset)
  199. {
  200. pwszPassword = reinterpret_cast<UNALIGNED WCHAR*>(static_cast<BYTE*>(pvBuffer) + pInfo->dwPasswordOffset);
  201. }
  202. else
  203. {
  204. pwszPassword = NULL;
  205. }
  206. if (pInfo->dwDataOffset)
  207. {
  208. pvData = static_cast<void*>(static_cast<BYTE*>(pvBuffer) + pInfo->dwDataOffset);
  209. }
  210. else
  211. {
  212. pvData = NULL;
  213. }
  214. if (pInfo->dwConnectDataOffset)
  215. {
  216. pvConnectData = (PVOID)((char *)pvBuffer + pInfo->dwConnectDataOffset);
  217. }
  218. else
  219. {
  220. pvConnectData = NULL;
  221. }
  222. if (pInfo->dwURLOffset)
  223. {
  224. #ifdef DPNBUILD_LIBINTERFACE
  225. hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
  226. reinterpret_cast<void**>(&pAddress));
  227. #else // ! DPNBUILD_LIBINTERFACE
  228. hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
  229. NULL,
  230. CLSCTX_INPROC_SERVER,
  231. IID_IDirectPlay8Address,
  232. reinterpret_cast<void**>(&pAddress),
  233. FALSE);
  234. #endif // ! DPNBUILD_LIBINTERFACE
  235. if (hResultCode != S_OK)
  236. {
  237. DPFERR("Could not create IDirectPlay8Address");
  238. DisplayDNError(0,hResultCode);
  239. DNASSERT(FALSE);
  240. return(hResultCode);
  241. }
  242. DPFX(DPFPREP, 5,"Connecting Player URL [%hs]",static_cast<char*>(pvBuffer) + pInfo->dwURLOffset);
  243. if ((hResultCode = IDirectPlay8Address_BuildFromURLA( pAddress,
  244. static_cast<char*>(pvBuffer) + pInfo->dwURLOffset )) != DPN_OK)
  245. {
  246. DPFERR("Could not build IDirectPlay8Address");
  247. DisplayDNError(0,hResultCode);
  248. DNASSERT(FALSE);
  249. goto Failure;
  250. }
  251. }
  252. else
  253. {
  254. DPFX(DPFPREP, 5,"No address URL specified - Host will have to determine it");
  255. if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
  256. {
  257. DPFERR("Could not retrieve EndPoint from Connection");
  258. DisplayDNError(0,hResultCode);
  259. DNASSERT(FALSE);
  260. goto Failure;
  261. }
  262. hResultCode = DNGetClearAddress(pdnObject,hEndPt,&pAddress,TRUE);
  263. pConnection->ReleaseEndPt(&CallbackThread);
  264. if (hResultCode != DPN_OK)
  265. {
  266. DPFERR("Could not determine Clear Address");
  267. DisplayDNError(0,hResultCode);
  268. DNASSERT(FALSE);
  269. goto Failure;
  270. }
  271. #ifdef DBG
  272. DP8ASize = 512;
  273. IDirectPlay8Address_GetURL(pAddress,DP8ABuffer,&DP8ASize);
  274. DPFX(DPFPREP, 5,"Remote Address [%s]",DP8ABuffer);
  275. #endif // DBG
  276. }
  277. #ifdef DBG
  278. if (pwszName != NULL)
  279. {
  280. if ((((DWORD_PTR) pwszName) % sizeof (WCHAR)) == 0)
  281. {
  282. DPFX(DPFPREP, 5,"Connecting Player: Name [%ls], Data Size [%ld], Connect Data Size [%ld]",
  283. pwszName,pInfo->dwDataSize,pInfo->dwConnectDataSize);
  284. }
  285. else
  286. {
  287. DPFX(DPFPREP, 5,"Connecting Player: Name [unaligned_name], Data Size [%ld], Connect Data Size [%ld]",
  288. pInfo->dwDataSize,pInfo->dwConnectDataSize);
  289. }
  290. }
  291. else
  292. {
  293. DPFX(DPFPREP, 5,"Connecting Player: No name, Data Size [%ld], Connect Data Size [%ld]",
  294. pInfo->dwDataSize,pInfo->dwConnectDataSize);
  295. }
  296. #endif // DBG
  297. //
  298. // Avoid alignment errors
  299. //
  300. GUID guidApplication;
  301. GUID guidInstance;
  302. guidApplication = pInfo->guidApplication;
  303. guidInstance = pInfo->guidInstance;
  304. //
  305. // Ensure this connect is valid
  306. //
  307. if ((hResultCode = DNHostVerifyConnect( pdnObject,
  308. pConnection,
  309. pInfo->dwFlags,
  310. pInfo->dwDNETVersion,
  311. pwszPassword,
  312. &guidApplication,
  313. &guidInstance,
  314. pvConnectData,
  315. pInfo->dwConnectDataSize,
  316. pAddress,
  317. &pvPlayerContext,
  318. &pvReplyBuffer,
  319. &dwReplyBufferSize,
  320. &pvReplyBufferContext)) != DPN_OK)
  321. {
  322. DPFX(DPFPREP, 5,"Connect failed, hResultCode = [0x%lx]",hResultCode);
  323. //
  324. // Disconnect this connection. We will also remove it from the indicated list.
  325. //
  326. DNEnterCriticalSection(&pdnObject->csConnectionList);
  327. if (!pConnection->m_bilinkIndicated.IsEmpty())
  328. {
  329. pConnection->Release();
  330. }
  331. pConnection->m_bilinkIndicated.RemoveFromList();
  332. DNLeaveCriticalSection(&pdnObject->csConnectionList);
  333. pConnection->Disconnect(); // Terminate this connection
  334. hResultCode = DPN_OK; // We handled everything okay !
  335. goto Failure; // For clean up
  336. }
  337. bPlayerVerified = TRUE;
  338. //
  339. // I am assuming that the player count has been updated by HostVerifyConnect.
  340. // That means that until we flag the connection as CONNECTed, we will manually
  341. // have to decrement it.
  342. //
  343. //
  344. // Create player entry
  345. //
  346. if ((hResultCode = NameTableEntryNew(pdnObject,&pNTEntry)) != DPN_OK)
  347. {
  348. DPFERR("Could not get new NameTableEntry");
  349. DisplayDNError(0,hResultCode);
  350. DNASSERT(FALSE);
  351. goto Failure;
  352. }
  353. // This function takes the lock internally
  354. pNTEntry->UpdateEntryInfo( pwszName,
  355. pInfo->dwNameSize,
  356. pvData,
  357. pInfo->dwDataSize,
  358. DPNINFO_NAME | DPNINFO_DATA,
  359. FALSE);
  360. pNTEntry->SetDNETVersion( pInfo->dwDNETVersion );
  361. if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  362. {
  363. pNTEntry->MakePeer();
  364. }
  365. else
  366. {
  367. pNTEntry->MakeClient();
  368. }
  369. if (pvPlayerContext)
  370. {
  371. pNTEntry->SetContext(pvPlayerContext);
  372. }
  373. pNTEntry->StartConnecting();
  374. pNTEntry->SetIndicated();
  375. pNTEntry->NotifyAddRef();
  376. pNTEntry->SetAddress(pAddress);
  377. IDirectPlay8Address_Release(pAddress);
  378. pAddress = NULL;
  379. //
  380. // Add player to NameTable
  381. //
  382. if ((hResultCode = pdnObject->NameTable.AddEntry(pNTEntry)) != DPN_OK)
  383. {
  384. pdnObject->NameTable.Unlock();
  385. DPFERR("Could not add entry to NameTable");
  386. DisplayDNError(0,hResultCode);
  387. goto Failure;
  388. }
  389. //
  390. // Set up connection
  391. // The connection should be "CONNECTING" or a disconnect has been issued since the NewPlayer sent
  392. // their connect info. Once the DPNID is set on the connection, the standard disconnect handler
  393. // will take care of clean up. If the DPNID is NOT set on the connection, the disconnect code
  394. // will just release the connection, without cleaning up the NameTable or the NameTableEntry.
  395. // Since the NameTable version may have changed since the NewPlayer was added, we will need to
  396. // delete the player from the NameTable (and generate a new version number). We will flag this
  397. // case, and just send out the DELETE_PLAYER message after sending out the ADD_PLAYER
  398. //
  399. pConnection->Lock();
  400. if (pConnection->IsConnecting())
  401. {
  402. pConnection->SetStatus( CONNECTED );
  403. fDisconnect = FALSE;
  404. }
  405. else
  406. {
  407. DPFX(DPFPREP, 5,"NewPlayer has disconnected while joining - send out ADD_PLAYER and then DELETE_PLAYER");
  408. fDisconnect = TRUE;
  409. }
  410. pConnection->SetDPNID( pNTEntry->GetDPNID() );
  411. pNTEntry->SetConnection( pConnection );
  412. pConnection->Unlock();
  413. //
  414. // Now that this connection is part of the NameTableEntry, remove it from the indicated list.
  415. //
  416. DNEnterCriticalSection(&pdnObject->csConnectionList);
  417. if (!pConnection->m_bilinkIndicated.IsEmpty())
  418. {
  419. pConnection->Release();
  420. }
  421. pConnection->m_bilinkIndicated.RemoveFromList();
  422. DNLeaveCriticalSection(&pdnObject->csConnectionList);
  423. //
  424. // Send name table to player
  425. //
  426. if (!fDisconnect)
  427. {
  428. hResultCode = DNSendConnectInfo(pdnObject,pNTEntry,pConnection,pvReplyBuffer,dwReplyBufferSize);
  429. if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
  430. {
  431. DPFERR("Could not send name table to player");
  432. DisplayDNError(0,hResultCode);
  433. DNASSERT(FALSE);
  434. #pragma TODO(minara,"Clean up here")
  435. goto Failure;
  436. }
  437. }
  438. if (pvReplyBuffer)
  439. {
  440. DNUserReturnBuffer(pdnObject,DPN_OK,pvReplyBuffer,pvReplyBufferContext);
  441. pvReplyBuffer = NULL;
  442. dwReplyBufferSize = 0;
  443. pvReplyBufferContext = NULL;
  444. }
  445. //
  446. // Setup name table entry to be passed to other players
  447. //
  448. if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  449. {
  450. packedBuffer.Initialize(NULL,0);
  451. if ((hResultCode = pNTEntry->PackEntryInfo(&packedBuffer)) != DPNERR_BUFFERTOOSMALL)
  452. {
  453. DPFERR("Unknown error encountered trying to pack NameTableEntry");
  454. DisplayDNError(0,hResultCode);
  455. DNASSERT(FALSE);
  456. goto Failure;
  457. }
  458. if ((hResultCode = RefCountBufferNew(pdnObject,packedBuffer.GetSizeRequired(),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  459. {
  460. DPFERR("Could not create new RefCountBuffer");
  461. DisplayDNError(0,hResultCode);
  462. DNASSERT(FALSE);
  463. goto Failure;
  464. }
  465. packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
  466. if ((hResultCode = pNTEntry->PackEntryInfo(&packedBuffer)) != DPN_OK)
  467. {
  468. DPFERR("Could not pack NameTableEntry");
  469. DisplayDNError(0,hResultCode);
  470. DNASSERT(FALSE);
  471. goto Failure;
  472. }
  473. //
  474. // Send ADD_PLAYER messages to other players (with lower versions)
  475. //
  476. if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
  477. {
  478. DPFERR("Could not create worker thread job (add player)");
  479. DisplayDNError(0,hResultCode);
  480. DNASSERT(FALSE);
  481. goto Failure;
  482. }
  483. pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
  484. pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_ADD_PLAYER );
  485. pWorkerJob->SetSendNameTableOperationVersion( pNTEntry->GetVersion() );
  486. pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
  487. pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
  488. DNQueueWorkerJob(pdnObject,pWorkerJob);
  489. pWorkerJob = NULL;
  490. pRefCountBuffer->Release();
  491. pRefCountBuffer = NULL;
  492. }
  493. //
  494. // If we were in the process of disconnecting, we will need to clean up now
  495. //
  496. if (fDisconnect)
  497. {
  498. DNHostDisconnect(pdnObject,pNTEntry->GetDPNID(),DPNDESTROYPLAYERREASON_NORMAL);
  499. }
  500. pNTEntry->Release();
  501. pNTEntry = NULL;
  502. // Now, wait for synchronization (player has loaded name table)
  503. hResultCode = DPN_OK;
  504. Exit:
  505. CallbackThread.Deinitialize();
  506. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  507. return(hResultCode);
  508. Failure:
  509. if (pvReplyBuffer)
  510. {
  511. //
  512. // Return buffer to HostPlayer
  513. //
  514. DNUserReturnBuffer(pdnObject,DPN_OK,pvReplyBuffer,pvReplyBufferContext);
  515. pvReplyBuffer = NULL;
  516. dwReplyBufferSize = 0;
  517. pvReplyBufferContext = NULL;
  518. }
  519. if (bPlayerVerified)
  520. {
  521. pdnObject->ApplicationDesc.DecPlayerCount();
  522. }
  523. if (pAddress)
  524. {
  525. IDirectPlay8Address_Release(pAddress);
  526. pAddress = NULL;
  527. }
  528. if (pNTEntry)
  529. {
  530. pNTEntry->Release();
  531. pNTEntry = NULL;
  532. }
  533. if (pAllPlayersGroup)
  534. {
  535. pAllPlayersGroup->Release();
  536. pAllPlayersGroup = NULL;
  537. }
  538. if (pRefCountBuffer)
  539. {
  540. pRefCountBuffer->Release();
  541. pRefCountBuffer = NULL;
  542. }
  543. goto Exit;
  544. }
  545. // DNHostConnect2
  546. //
  547. // Mark player as "available" in NameTable
  548. // Send INSTRUCT_CONNECT messages to the existing players to add new player
  549. //
  550. // CConnection *pConnection Connection for connecting player
  551. //
  552. #undef DPF_MODNAME
  553. #define DPF_MODNAME "DNHostConnect2"
  554. HRESULT DNHostConnect2(DIRECTNETOBJECT *const pdnObject,
  555. CConnection *const pConnection)
  556. {
  557. HRESULT hResultCode;
  558. DPNID dpnid;
  559. CRefCountBuffer *pRefCountBuffer;
  560. CNameTableEntry *pNTEntry;
  561. CWorkerJob *pWorkerJob;
  562. DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT *pInfo;
  563. DPFX(DPFPREP, 4,"Parameters: pConnection [0x%p]",pConnection);
  564. DNASSERT(pdnObject != NULL);
  565. DNASSERT(pConnection != NULL);
  566. pRefCountBuffer = NULL;
  567. pNTEntry = NULL;
  568. pWorkerJob = NULL;
  569. pConnection->Lock();
  570. dpnid = pConnection->GetDPNID();
  571. pConnection->Unlock();
  572. pdnObject->NameTable.PopulateConnection(pConnection);
  573. //
  574. // Instruct existing players to connect to NewPlayer
  575. //
  576. if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  577. {
  578. DPFX(DPFPREP, 5,"Instruct existing players to connect to NewPlayer [0x%lx]",dpnid);
  579. // Need version number of this player
  580. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  581. {
  582. DPFERR("Could not find player in nametable");
  583. DisplayDNError(0,hResultCode);
  584. // DNASSERT(FALSE);
  585. goto Failure;
  586. }
  587. hResultCode = RefCountBufferNew(pdnObject,
  588. sizeof(DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT),
  589. MemoryBlockAlloc,
  590. MemoryBlockFree,
  591. &pRefCountBuffer);
  592. if (hResultCode != DPN_OK)
  593. {
  594. DPFERR("Could not create CountBuffer");
  595. DisplayDNError(0,hResultCode);
  596. DNASSERT(FALSE);
  597. goto Failure;
  598. }
  599. pInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT*>(pRefCountBuffer->GetBufferAddress());
  600. pInfo->dpnid = dpnid;
  601. pdnObject->NameTable.WriteLock();
  602. pdnObject->NameTable.GetNewVersion( &pInfo->dwVersion );
  603. pdnObject->NameTable.Unlock();
  604. pInfo->dwVersionNotUsed = 0;
  605. if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
  606. {
  607. DPFERR("Could not create worker thread job (add player)");
  608. DisplayDNError(0,hResultCode);
  609. DNASSERT(FALSE);
  610. goto Failure;
  611. }
  612. pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
  613. pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_INSTRUCT_CONNECT );
  614. pWorkerJob->SetSendNameTableOperationVersion( pInfo->dwVersion );
  615. pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
  616. pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
  617. DNQueueWorkerJob(pdnObject,pWorkerJob);
  618. pWorkerJob = NULL;
  619. pNTEntry->Release();
  620. pNTEntry = NULL;
  621. pRefCountBuffer->Release();
  622. pRefCountBuffer = NULL;
  623. }
  624. hResultCode = DPN_OK;
  625. Exit:
  626. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  627. return(hResultCode);
  628. Failure:
  629. if (pRefCountBuffer)
  630. {
  631. pRefCountBuffer->Release();
  632. pRefCountBuffer = NULL;
  633. }
  634. if (pNTEntry)
  635. {
  636. pNTEntry->Release();
  637. pNTEntry = NULL;
  638. }
  639. goto Exit;
  640. }
  641. // DNHostVerifyConnect
  642. //
  643. // Host connection verification. Ensure that the player connecting meets ALL criteria
  644. // including:
  645. // correct mode (client/server or peer/peer)
  646. // correct instance guid
  647. // correct application (if specified)
  648. // correct password (if specified)
  649. // correct user spec (through call-back)
  650. //
  651. #undef DPF_MODNAME
  652. #define DPF_MODNAME "DNHostVerifyConnect"
  653. HRESULT DNHostVerifyConnect(DIRECTNETOBJECT *const pdnObject,
  654. CConnection *const pConnection,
  655. const DWORD dwFlags,
  656. const DWORD dwDNETVersion,
  657. UNALIGNED WCHAR *const pwszPassword,
  658. GUID *const pguidApplication,
  659. GUID *const pguidInstance,
  660. PVOID const pvConnectData,
  661. const DWORD dwConnectDataSize,
  662. IDirectPlay8Address *const pAddress,
  663. void **const ppvPlayerContext,
  664. void **const ppvReplyBuffer,
  665. DWORD *const pdwReplyBufferSize,
  666. void **const ppvReplyBufferContext)
  667. {
  668. HRESULT hResultCode;
  669. HRESULT hrFailure;
  670. PVOID pvReplyData;
  671. DWORD dwReplyDataSize;
  672. PVOID pvReplyContext;
  673. DWORD dwBufferSize;
  674. HANDLE hEndPt;
  675. CNameTableEntry *pLocalPlayer;
  676. CRefCountBuffer *pRefCountBuffer;
  677. CPackedBuffer packedBuffer;
  678. IDirectPlay8Address *pDevice;
  679. DN_INTERNAL_MESSAGE_CONNECT_FAILED *pInfo;
  680. BOOL fDecPlayerCount;
  681. CCallbackThread CallbackThread;
  682. GUID guidnull;
  683. #ifdef DBG
  684. TCHAR DP8ABuffer[512] = {0};
  685. DWORD DP8ASize;
  686. #endif // DBG
  687. DPFX(DPFPREP, 6,"Parameters: dwFlags [0x%lx], dwDPlay8Version [0x%lx], pwszPassword [0x%p], pguidApplication [0x%p], pguidInstance [0x%p], pvConnectData [0x%p], dwConnectDataSize [%ld]",
  688. dwFlags,dwDNETVersion,pwszPassword,pguidApplication,pguidInstance,pvConnectData,dwConnectDataSize);
  689. DNASSERT(pdnObject != NULL);
  690. DNASSERT(ppvReplyBuffer != NULL);
  691. DNASSERT(pdwReplyBufferSize != NULL);
  692. DNASSERT(ppvReplyBufferContext != NULL);
  693. pLocalPlayer = NULL;
  694. pRefCountBuffer = NULL;
  695. pvReplyData = NULL;
  696. dwReplyDataSize = 0;
  697. pvReplyContext = NULL;
  698. pDevice = NULL;
  699. fDecPlayerCount = FALSE;
  700. memset(&guidnull, 0, sizeof(guidnull));
  701. CallbackThread.Initialize();
  702. //
  703. // Ensure we're not closing or host migrating
  704. //
  705. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  706. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)
  707. {
  708. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  709. hResultCode = DPNERR_ALREADYCLOSING;
  710. goto CleanUp;
  711. }
  712. if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING)
  713. {
  714. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  715. hResultCode = DPNERR_NOTHOST;
  716. goto Failure;
  717. }
  718. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  719. //
  720. // Ensure we are the Host
  721. //
  722. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  723. {
  724. DPFERR("Connection received by non-host player");
  725. hResultCode = DPNERR_NOTHOST;
  726. goto Failure;
  727. }
  728. if (!pLocalPlayer->IsHost())
  729. {
  730. DPFERR("Connection received by non-host player");
  731. hResultCode = DPNERR_NOTHOST;
  732. goto Failure;
  733. }
  734. pLocalPlayer->Release();
  735. pLocalPlayer = NULL;
  736. //
  737. // Verify Mode
  738. //
  739. if ((pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) && !(dwFlags & DN_OBJECT_FLAG_PEER))
  740. {
  741. DPFX(DPFPREP, 7,"Non peer player attempting connection to peer");
  742. hResultCode = DPNERR_INVALIDINTERFACE;
  743. goto Failure;
  744. }
  745. #ifndef DPNBUILD_NOSERVER
  746. if ((pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) && !(dwFlags & DN_OBJECT_FLAG_CLIENT))
  747. {
  748. DPFX(DPFPREP, 7,"Non client player attempting connection to server");
  749. hResultCode = DPNERR_INVALIDINTERFACE;
  750. goto Failure;
  751. }
  752. #endif // DPNBUILD_NOSERVER
  753. //
  754. // Verify DNET version - we will only compare the high 16-bits (major number)
  755. // - we will allow different low 16-bits (minor number)
  756. //
  757. if ((dwDNETVersion & 0xffff0000) != (DN_VERSION_CURRENT & 0xffff0000))
  758. {
  759. DPFX(DPFPREP, 7,"Invalid DPlay8 version!");
  760. hResultCode = DPNERR_INVALIDVERSION;
  761. goto Failure;
  762. }
  763. //
  764. // Validate instance GUID
  765. //
  766. if (pguidInstance && (*pguidInstance != guidnull))
  767. {
  768. if (!pdnObject->ApplicationDesc.IsEqualInstanceGuid(pguidInstance))
  769. {
  770. DPFERR("Invalid Instance GUID specified at connection");
  771. hResultCode = DPNERR_INVALIDINSTANCE;
  772. goto Failure;
  773. }
  774. }
  775. //
  776. // Validate application (if specified)
  777. //
  778. if (pguidApplication && (*pguidApplication != guidnull))
  779. {
  780. if (!pdnObject->ApplicationDesc.IsEqualApplicationGuid(pguidApplication))
  781. {
  782. DPFERR("Invalid Application GUID specified at connection");
  783. hResultCode = DPNERR_INVALIDAPPLICATION;
  784. goto Failure;
  785. }
  786. }
  787. //
  788. // Validate password
  789. //
  790. if (!pdnObject->ApplicationDesc.IsEqualPassword(pwszPassword))
  791. {
  792. DPFERR("Incorrect password (required) specified at connection");
  793. hResultCode = DPNERR_INVALIDPASSWORD;
  794. goto Failure;
  795. }
  796. //
  797. // Get device address this connection came in on
  798. //
  799. if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
  800. {
  801. DPFERR("Could not extract endpoint from CConnection");
  802. DisplayDNError(0,hResultCode);
  803. hResultCode = DPNERR_GENERIC; // Is there a better one ?
  804. goto Failure;
  805. }
  806. hResultCode = DNGetLocalDeviceAddress(pdnObject,hEndPt,&pDevice);
  807. pConnection->ReleaseEndPt(&CallbackThread);
  808. if (hResultCode != DPN_OK)
  809. {
  810. DPFERR("Could not determine local device address");
  811. DisplayDNError(0,hResultCode);
  812. hResultCode = DPNERR_GENERIC; // Is there a better one ?
  813. goto Failure;
  814. }
  815. #ifdef DBG
  816. DP8ASize = 512;
  817. IDirectPlay8Address_GetURL(pDevice,DP8ABuffer,&DP8ASize);
  818. DPFX(DPFPREP, 5,"Local Device Address [%s]",DP8ABuffer);
  819. #endif // DBG
  820. //
  821. // Increment AppDesc count
  822. //
  823. hResultCode = pdnObject->ApplicationDesc.IncPlayerCount( TRUE );
  824. if (hResultCode != DPN_OK)
  825. {
  826. DPFX(DPFPREP, 7,"Could not add player to game");
  827. DisplayDNError(0,hResultCode);
  828. goto Failure;
  829. }
  830. fDecPlayerCount = TRUE; // only for error handling
  831. //
  832. // Validate user specified data (through call-back)
  833. //
  834. if (pvConnectData)
  835. {
  836. DPFX(DPFPREP, 7,"dwConnectDataSize [%ld]",dwConnectDataSize);
  837. }
  838. else
  839. {
  840. DPFX(DPFPREP, 7,"No connect data given");
  841. }
  842. if ((hResultCode = DNUserIndicateConnect( pdnObject,
  843. pvConnectData,
  844. dwConnectDataSize,
  845. &pvReplyData,
  846. &dwReplyDataSize,
  847. &pvReplyContext,
  848. pAddress,
  849. pDevice,
  850. ppvPlayerContext)) != DPN_OK)
  851. {
  852. DPFERR("Application declined connection attempt");
  853. hResultCode = DPNERR_HOSTREJECTEDCONNECTION;
  854. goto Failure;
  855. }
  856. IDirectPlay8Address_Release(pDevice);
  857. pDevice = NULL;
  858. //
  859. // Save reply buffer
  860. //
  861. if ((pvReplyData) && (dwReplyDataSize != 0))
  862. {
  863. *ppvReplyBuffer = pvReplyData;
  864. *pdwReplyBufferSize = dwReplyDataSize;
  865. *ppvReplyBufferContext = pvReplyContext;
  866. }
  867. else
  868. {
  869. *ppvReplyBuffer = NULL;
  870. *pdwReplyBufferSize = 0;
  871. *ppvReplyBufferContext = NULL;
  872. }
  873. Exit:
  874. CallbackThread.Deinitialize();
  875. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  876. return(hResultCode);
  877. Failure:
  878. if (fDecPlayerCount)
  879. {
  880. pdnObject->ApplicationDesc.DecPlayerCount();
  881. }
  882. //
  883. // Send a message back to the connecting player that this failed
  884. //
  885. DPFX(DPFPREP, 7,"Connect failed [0x%lx]",hResultCode);
  886. hrFailure = hResultCode;
  887. if (pvReplyData == NULL)
  888. {
  889. dwReplyDataSize = 0; // basic validation
  890. }
  891. dwBufferSize = sizeof(DN_INTERNAL_MESSAGE_CONNECT_FAILED) + dwReplyDataSize;
  892. DPFX(DPFPREP, 7,"Failure buffer is [%ld] bytes",dwBufferSize);
  893. //
  894. // Create and fill failure message buffer
  895. //
  896. if ((hResultCode = RefCountBufferNew(pdnObject,dwBufferSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  897. {
  898. DPFERR("Could not create RefCountBuffer");
  899. DisplayDNError(0,hResultCode);
  900. goto CleanUp;
  901. }
  902. packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
  903. pInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_CONNECT_FAILED*>(pRefCountBuffer->GetBufferAddress());
  904. if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CONNECT_FAILED))) != DPN_OK)
  905. {
  906. DPFERR("Could not add header to message buffer");
  907. DisplayDNError(0,hResultCode);
  908. goto CleanUp;
  909. }
  910. if (pvReplyData)
  911. {
  912. if ((hResultCode = packedBuffer.AddToBack(pvReplyData,dwReplyDataSize)) != DPN_OK)
  913. {
  914. DPFERR("Could not add reply to failure buffer");
  915. DisplayDNError(0,hResultCode);
  916. goto CleanUp;
  917. }
  918. pInfo->dwReplyOffset = packedBuffer.GetTailOffset();
  919. pInfo->dwReplySize = dwReplyDataSize;
  920. DNUserReturnBuffer(pdnObject,DPN_OK,pvReplyData,pvReplyContext); // Return buffer
  921. }
  922. else
  923. {
  924. pInfo->dwReplyOffset = 0;
  925. pInfo->dwReplySize = 0;
  926. }
  927. pInfo->hResultCode = hrFailure;
  928. //
  929. // Send failure message
  930. //
  931. hResultCode = DNSendMessage(pdnObject,
  932. pConnection,
  933. DN_MSG_INTERNAL_CONNECT_FAILED,
  934. NULL,
  935. pRefCountBuffer->BufferDescAddress(),
  936. 1,
  937. pRefCountBuffer,
  938. 0,
  939. DN_SENDFLAGS_RELIABLE,
  940. NULL,
  941. NULL);
  942. pRefCountBuffer->Release();
  943. pRefCountBuffer = NULL;
  944. CleanUp:
  945. if (pRefCountBuffer)
  946. {
  947. pRefCountBuffer->Release();
  948. pRefCountBuffer = NULL;
  949. }
  950. if (pLocalPlayer)
  951. {
  952. pLocalPlayer->Release();
  953. pLocalPlayer = NULL;
  954. }
  955. if (pDevice)
  956. {
  957. IDirectPlay8Address_Release(pDevice);
  958. pDevice = NULL;
  959. }
  960. goto Exit;
  961. }
  962. //
  963. // DNHostDropPlayer
  964. //
  965. // An existing player in a peer-peer game could not connect to a NewPlayer and is informing the
  966. // Host of this situation. As a result, the Host will drop inform the NewPlayer of this and then
  967. // drop the NewPlayer from the game
  968. //
  969. #undef DPF_MODNAME
  970. #define DPF_MODNAME "DNHostDropPlayer"
  971. HRESULT DNHostDropPlayer(DIRECTNETOBJECT *const pdnObject,
  972. const DPNID dpnid, // ExistingPlayer who could not connect to NewPlayer
  973. void *const pvBuffer)
  974. {
  975. HRESULT hResultCode;
  976. CRefCountBuffer *pRefCountBuffer;
  977. CNameTableEntry *pNTEntry;
  978. CConnection *pConnection;
  979. UNALIGNED DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED *pInfo;
  980. DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED *pMsg;
  981. DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
  982. DNASSERT(pdnObject != NULL);
  983. DNASSERT(pvBuffer != NULL);
  984. pRefCountBuffer = NULL;
  985. pNTEntry = NULL;
  986. pConnection = NULL;
  987. pInfo = static_cast<DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED*>(pvBuffer);
  988. DPFX(DPFPREP, 5,"Connection to [0x%lx] failed",pInfo->dpnid);
  989. //
  990. // Get connection for NewPlayer
  991. //
  992. if ((hResultCode = pdnObject->NameTable.FindEntry(pInfo->dpnid,&pNTEntry)) != DPN_OK)
  993. {
  994. DPFERR("NewPlayer no longer in NameTable - not to worry");
  995. hResultCode = DPN_OK;
  996. goto Failure;
  997. }
  998. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
  999. {
  1000. DPFERR("Connection for NewPlayer no longer valid - not to worry");
  1001. hResultCode = DPN_OK;
  1002. goto Failure;
  1003. }
  1004. pNTEntry->Release();
  1005. pNTEntry = NULL;
  1006. //
  1007. // Send message to NewPlayer informing them of which existing player could not connect to them
  1008. //
  1009. hResultCode = RefCountBufferNew(pdnObject,
  1010. sizeof(DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED),
  1011. MemoryBlockAlloc,
  1012. MemoryBlockFree,
  1013. &pRefCountBuffer);
  1014. if (hResultCode != DPN_OK)
  1015. {
  1016. DPFERR("Could not allocate RefCountBuffer");
  1017. DisplayDNError(0,hResultCode);
  1018. DNASSERT(FALSE);
  1019. goto Failure;
  1020. }
  1021. pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED*>(pRefCountBuffer->GetBufferAddress());
  1022. pMsg->dpnid = dpnid;
  1023. hResultCode = DNSendMessage(pdnObject,
  1024. pConnection,
  1025. DN_MSG_INTERNAL_CONNECT_ATTEMPT_FAILED,
  1026. pInfo->dpnid,
  1027. pRefCountBuffer->BufferDescAddress(),
  1028. 1,
  1029. pRefCountBuffer,
  1030. 0,
  1031. DN_SENDFLAGS_RELIABLE,
  1032. NULL,
  1033. NULL);
  1034. if (hResultCode != DPNERR_PENDING)
  1035. {
  1036. DPFERR("Could not send message to NewPlayer - assume he is gone or going");
  1037. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  1038. hResultCode = DPN_OK;
  1039. goto Failure;
  1040. }
  1041. pRefCountBuffer->Release();
  1042. pRefCountBuffer = NULL;
  1043. //
  1044. // We will just drop (or at least attempt to drop) the connection
  1045. //
  1046. pConnection->Disconnect();
  1047. pConnection->Release();
  1048. pConnection = NULL;
  1049. hResultCode = DNHostDisconnect(pdnObject,pInfo->dpnid,DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
  1050. hResultCode = DPN_OK;
  1051. Exit:
  1052. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  1053. return(hResultCode);
  1054. Failure:
  1055. if (pRefCountBuffer)
  1056. {
  1057. pRefCountBuffer->Release();
  1058. pRefCountBuffer = NULL;
  1059. }
  1060. if (pNTEntry)
  1061. {
  1062. pNTEntry->Release();
  1063. pNTEntry = NULL;
  1064. }
  1065. if (pConnection)
  1066. {
  1067. pConnection->Release();
  1068. pConnection = NULL;
  1069. }
  1070. goto Exit;
  1071. }
  1072. //
  1073. // Perform a connection to a host player (either host in peer-to-peer or server in client-server).
  1074. // This processes the handshaking of the name table between the host and the player.
  1075. // The first step is to send the player and application info to the host for verification
  1076. // The second step is to receive and process the name table from the host
  1077. // The last step is to wait for connections from other players and populate the name table
  1078. // It assumes that the connection to the host has already been initiated.
  1079. //
  1080. // DNPrepareConnectInfo
  1081. //
  1082. // Prepare the connection info block which will be sent to the Host player once a connection
  1083. // has been established.
  1084. #undef DPF_MODNAME
  1085. #define DPF_MODNAME "DNPrepareConnectInfo"
  1086. HRESULT DNPrepareConnectInfo(DIRECTNETOBJECT *const pdnObject,
  1087. CConnection *const pConnection,
  1088. CRefCountBuffer **const ppRefCountBuffer)
  1089. {
  1090. HRESULT hResultCode;
  1091. DWORD dwSize;
  1092. DWORD dwPasswordSize;
  1093. DWORD dwAddressSize;
  1094. HANDLE hEndPt;
  1095. CRefCountBuffer *pRefCountBuffer;
  1096. CPackedBuffer packedBuffer;
  1097. IDirectPlay8Address *pAddress;
  1098. DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO *pInfo;
  1099. CCallbackThread CallbackThread;
  1100. #ifdef DBG
  1101. TCHAR DP8ABuffer[512] = {0};
  1102. DWORD DP8ASize;
  1103. #endif // DBG
  1104. DPFX(DPFPREP, 4,"Parameters: pConnection [0x%p], ppRefCountBuffer [0x%p]",pConnection,ppRefCountBuffer);
  1105. DNASSERT(pdnObject != NULL);
  1106. DNASSERT(pConnection != NULL);
  1107. DNASSERT(ppRefCountBuffer != NULL);
  1108. pRefCountBuffer = NULL;
  1109. pAddress = NULL;
  1110. dwAddressSize = 0;
  1111. CallbackThread.Initialize();
  1112. //
  1113. // Get clear address
  1114. //
  1115. dwAddressSize = 0;
  1116. if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) == DPN_OK)
  1117. {
  1118. if ((hResultCode = DNGetClearAddress(pdnObject,hEndPt,&pAddress,FALSE)) == DPN_OK)
  1119. {
  1120. if (pAddress != NULL)
  1121. {
  1122. // Get address URL size
  1123. IDirectPlay8Address_GetURL(pAddress,NULL,&dwAddressSize);
  1124. DNASSERT(dwAddressSize != 0);
  1125. #ifdef DBG
  1126. DP8ASize = 512;
  1127. IDirectPlay8Address_GetURL(pAddress,DP8ABuffer,&DP8ASize);
  1128. DPFX(DPFPREP, 5,"Remote Address [%s]",DP8ABuffer);
  1129. #endif // DBG
  1130. }
  1131. }
  1132. pConnection->ReleaseEndPt(&CallbackThread);
  1133. }
  1134. // Determine total size of connection info buffer
  1135. if (pdnObject->ApplicationDesc.GetPassword() != NULL)
  1136. dwPasswordSize = (wcslen(pdnObject->ApplicationDesc.GetPassword()) + 1) * sizeof(WCHAR);
  1137. else
  1138. dwPasswordSize = 0;
  1139. DNASSERT(pdnObject->NameTable.GetDefaultPlayer() != NULL);
  1140. dwSize = sizeof(DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO)
  1141. + pdnObject->dwConnectDataSize
  1142. + dwAddressSize
  1143. + dwPasswordSize
  1144. + pdnObject->NameTable.GetDefaultPlayer()->GetDataSize()
  1145. + pdnObject->NameTable.GetDefaultPlayer()->GetNameSize();
  1146. // Allocate connection info buffer
  1147. DPFX(DPFPREP, 7,"Need to allocate [%ld] bytes",dwSize);
  1148. if ((hResultCode = RefCountBufferNew(pdnObject,dwSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  1149. {
  1150. DPFERR("Could not allocate space for connection info");
  1151. DisplayDNError(0,hResultCode);
  1152. DNASSERT(FALSE);
  1153. goto Failure;
  1154. }
  1155. packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
  1156. pInfo = static_cast<DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO*>(packedBuffer.GetHeadAddress());
  1157. // Type of interface
  1158. #ifndef DPNBUILD_NOSERVER
  1159. pInfo->dwFlags = pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER | DN_OBJECT_FLAG_CLIENT | DN_OBJECT_FLAG_SERVER);
  1160. #else
  1161. pInfo->dwFlags = pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER | DN_OBJECT_FLAG_CLIENT);
  1162. #endif // DPNBUILD_NOSERVER
  1163. // Version of DIRECTNET
  1164. pInfo->dwDNETVersion = DN_VERSION_CURRENT;
  1165. // Name
  1166. if (pdnObject->NameTable.GetDefaultPlayer()->GetNameSize())
  1167. {
  1168. if ((hResultCode = packedBuffer.AddToBack(pdnObject->NameTable.GetDefaultPlayer()->GetName(),
  1169. pdnObject->NameTable.GetDefaultPlayer()->GetNameSize())) != DPN_OK)
  1170. {
  1171. DPFERR("Could not add name to connection buffer");
  1172. DisplayDNError(0,hResultCode);
  1173. DNASSERT(FALSE);
  1174. goto Failure;
  1175. }
  1176. pInfo->dwNameOffset = packedBuffer.GetTailOffset();
  1177. pInfo->dwNameSize = pdnObject->NameTable.GetDefaultPlayer()->GetNameSize();
  1178. }
  1179. else
  1180. {
  1181. pInfo->dwNameOffset = 0;
  1182. pInfo->dwNameSize = 0;
  1183. }
  1184. // Player data
  1185. if (pdnObject->NameTable.GetDefaultPlayer()->GetData() && pdnObject->NameTable.GetDefaultPlayer()->GetDataSize())
  1186. {
  1187. if ((hResultCode = packedBuffer.AddToBack(pdnObject->NameTable.GetDefaultPlayer()->GetData(),
  1188. pdnObject->NameTable.GetDefaultPlayer()->GetDataSize())) != DPN_OK)
  1189. {
  1190. DPFERR("Could not add connect data to connection buffer");
  1191. DisplayDNError(0,hResultCode);
  1192. DNASSERT(FALSE);
  1193. goto Failure;
  1194. }
  1195. pInfo->dwDataOffset = packedBuffer.GetTailOffset();
  1196. pInfo->dwDataSize = pdnObject->NameTable.GetDefaultPlayer()->GetDataSize();
  1197. }
  1198. else
  1199. {
  1200. pInfo->dwDataOffset = 0;
  1201. pInfo->dwDataSize = 0;
  1202. }
  1203. // Password
  1204. if (dwPasswordSize)
  1205. {
  1206. if ((hResultCode = packedBuffer.AddToBack(pdnObject->ApplicationDesc.GetPassword(),dwPasswordSize)) != DPN_OK)
  1207. {
  1208. DPFERR("Could not add password to connection buffer");
  1209. DisplayDNError(0,hResultCode);
  1210. DNASSERT(FALSE);
  1211. goto Failure;
  1212. }
  1213. pInfo->dwPasswordOffset = packedBuffer.GetTailOffset();
  1214. pInfo->dwPasswordSize = dwPasswordSize;
  1215. }
  1216. else
  1217. {
  1218. pInfo->dwPasswordOffset = 0;
  1219. pInfo->dwPasswordSize = 0;
  1220. }
  1221. // Connect data
  1222. if (pdnObject->pvConnectData)
  1223. {
  1224. if ((hResultCode = packedBuffer.AddToBack(pdnObject->pvConnectData,pdnObject->dwConnectDataSize)) != DPN_OK)
  1225. {
  1226. DPFERR("Could not add connect data to connection buffer");
  1227. DisplayDNError(0,hResultCode);
  1228. DNASSERT(FALSE);
  1229. goto Failure;
  1230. }
  1231. pInfo->dwConnectDataOffset = packedBuffer.GetTailOffset();
  1232. pInfo->dwConnectDataSize = pdnObject->dwConnectDataSize;
  1233. }
  1234. else
  1235. {
  1236. pInfo->dwConnectDataOffset = 0;
  1237. pInfo->dwConnectDataSize = 0;
  1238. }
  1239. // Clear address URL
  1240. if (dwAddressSize)
  1241. {
  1242. if ((hResultCode = packedBuffer.AddToBack(NULL,dwAddressSize)) != DPN_OK)
  1243. {
  1244. DPFERR("Could not add address URL to connection buffer");
  1245. DisplayDNError(0,hResultCode);
  1246. DNASSERT(FALSE);
  1247. goto Failure;
  1248. }
  1249. if ((hResultCode = IDirectPlay8Address_GetURLA(pAddress,
  1250. static_cast<char*>(packedBuffer.GetTailAddress()),
  1251. &dwAddressSize)) != DPN_OK)
  1252. {
  1253. DPFERR("Could not get address URL");
  1254. DisplayDNError(0,hResultCode);
  1255. DNASSERT(FALSE);
  1256. goto Failure;
  1257. }
  1258. pInfo->dwURLOffset = packedBuffer.GetTailOffset();
  1259. pInfo->dwURLSize = dwAddressSize;
  1260. }
  1261. else
  1262. {
  1263. pInfo->dwURLOffset = 0;
  1264. pInfo->dwURLSize = 0;
  1265. }
  1266. // Instance and appplication GUIDs
  1267. memcpy(&pInfo->guidInstance,pdnObject->ApplicationDesc.GetInstanceGuid(),sizeof(GUID));
  1268. memcpy(&pInfo->guidApplication,pdnObject->ApplicationDesc.GetApplicationGuid(),sizeof(GUID));
  1269. *ppRefCountBuffer = pRefCountBuffer;
  1270. pRefCountBuffer = NULL;
  1271. if (pAddress)
  1272. {
  1273. IDirectPlay8Address_Release(pAddress);
  1274. pAddress = NULL;
  1275. }
  1276. hResultCode = DPN_OK;
  1277. Exit:
  1278. CallbackThread.Deinitialize();
  1279. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  1280. return(hResultCode);
  1281. Failure:
  1282. if (pRefCountBuffer)
  1283. {
  1284. pRefCountBuffer->Release();
  1285. pRefCountBuffer = NULL;
  1286. }
  1287. if (pAddress)
  1288. {
  1289. IDirectPlay8Address_Release(pAddress);
  1290. pAddress = NULL;
  1291. }
  1292. goto Exit;
  1293. }
  1294. // DNConnectToHost1
  1295. //
  1296. // After receiving protocol level connection acknowledgement, send player and application info
  1297. // CConnection *pConnection Connection to host
  1298. #undef DPF_MODNAME
  1299. #define DPF_MODNAME "DNConnectToHost1"
  1300. HRESULT DNConnectToHost1(DIRECTNETOBJECT *const pdnObject,
  1301. CConnection *const pConnection)
  1302. {
  1303. HRESULT hResultCode;
  1304. CRefCountBuffer *pRefCountBuffer;
  1305. CAsyncOp *pAsyncOp;
  1306. CAsyncOp *pConnectParent;
  1307. DPFX(DPFPREP, 4,"Parameters: pConnection [0x%p]",pConnection);
  1308. DNASSERT(pdnObject != NULL);
  1309. DNASSERT(pConnection != NULL);
  1310. pRefCountBuffer = NULL;
  1311. pAsyncOp = NULL;
  1312. pConnectParent = NULL;
  1313. //
  1314. // Get connect parent (and make sure we're not closing)
  1315. // We will also store the CConnection on the connect parent for future clean up.
  1316. //
  1317. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1318. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING))
  1319. {
  1320. DPFERR("Object is CLOSING or DISCONNECTING");
  1321. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1322. pConnection->Disconnect();
  1323. hResultCode = DPN_OK;
  1324. goto Failure;
  1325. }
  1326. DNASSERT(pdnObject->pConnectParent != NULL);
  1327. pdnObject->pConnectParent->SetConnection( pConnection );
  1328. pdnObject->pConnectParent->AddRef();
  1329. pConnectParent = pdnObject->pConnectParent;
  1330. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1331. //
  1332. // Prepare connect info
  1333. //
  1334. if ((hResultCode = DNPrepareConnectInfo(pdnObject,pConnection,&pRefCountBuffer)) != DPN_OK)
  1335. {
  1336. DPFERR("Could not prepare connect info");
  1337. DisplayDNError(0,hResultCode);
  1338. DNASSERT(FALSE);
  1339. goto Failure;
  1340. }
  1341. DNASSERT(pRefCountBuffer != NULL);
  1342. //
  1343. // Send connect info
  1344. //
  1345. hResultCode = DNSendMessage(pdnObject,
  1346. pConnection,
  1347. DN_MSG_INTERNAL_PLAYER_CONNECT_INFO,
  1348. 0,
  1349. pRefCountBuffer->BufferDescAddress(),
  1350. 1,
  1351. pRefCountBuffer,
  1352. 0,
  1353. DN_SENDFLAGS_RELIABLE,
  1354. pConnectParent,
  1355. &pAsyncOp);
  1356. if (hResultCode == DPNERR_PENDING)
  1357. {
  1358. pAsyncOp->SetCompletion( DNCompleteSendConnectInfo );
  1359. pAsyncOp->Release();
  1360. pAsyncOp = NULL;
  1361. hResultCode = DPN_OK;
  1362. }
  1363. else
  1364. {
  1365. //
  1366. // Save error code, clean up DirectNetObject and fail
  1367. //
  1368. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  1369. DNAbortConnect(pdnObject,hResultCode);
  1370. }
  1371. pConnectParent->Release();
  1372. pConnectParent = NULL;
  1373. pRefCountBuffer->Release();
  1374. pRefCountBuffer = NULL;
  1375. Exit:
  1376. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  1377. return(hResultCode);
  1378. Failure:
  1379. if (pConnectParent)
  1380. {
  1381. pConnectParent->Release();
  1382. pConnectParent = NULL;
  1383. }
  1384. goto Exit;
  1385. }
  1386. // DN_ConnectToHost2
  1387. //
  1388. // Extract and install the host supplied name table
  1389. // Send name table acknowledgement to the host
  1390. // Propegate ADD_PLAYER messages to the application for host and local players
  1391. // Propegate CREATE_GROUP messages to the application for groups in the name table
  1392. //
  1393. // PVOID pvData NameTable buffer
  1394. // CConnection *pConnection Connection to host
  1395. #undef DPF_MODNAME
  1396. #define DPF_MODNAME "DNConnectToHost2"
  1397. HRESULT DNConnectToHost2(DIRECTNETOBJECT *const pdnObject,
  1398. const PVOID pvData,
  1399. CConnection *const pConnection)
  1400. {
  1401. HRESULT hResultCode;
  1402. CNameTableEntry *pNTEntry;
  1403. CNameTableEntry *pHostPlayer;
  1404. CNameTableEntry *pLocalPlayer;
  1405. CNameTableOp *pNTOp;
  1406. CBilink *pBilink;
  1407. DPNID dpnid;
  1408. DWORD dwFlags;
  1409. CConnection *pLocalConnection;
  1410. BOOL fNotify;
  1411. IDirectPlay8Address *pIDevice;
  1412. IDirectPlay8Address *pIHost;
  1413. CAsyncOp *pListenParent;
  1414. CAsyncOp *pConnectParent;
  1415. HANDLE hEndPt;
  1416. CCallbackThread CallbackThread;
  1417. DPFX(DPFPREP, 4,"Parameters: pvData [0x%p], pConnection [0x%p]",pvData,pConnection);
  1418. DNASSERT(pdnObject != NULL);
  1419. DNASSERT(pvData != NULL);
  1420. DNASSERT(pConnection != NULL);
  1421. pNTEntry = NULL;
  1422. pHostPlayer = NULL;
  1423. pLocalPlayer = NULL;
  1424. pLocalConnection = NULL;
  1425. pIDevice = NULL;
  1426. pIHost = NULL;
  1427. pListenParent = NULL;
  1428. pConnectParent = NULL;
  1429. CallbackThread.Initialize();
  1430. //
  1431. // Initial try to catch a close
  1432. //
  1433. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1434. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING))
  1435. {
  1436. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1437. hResultCode = DPN_OK;
  1438. goto Failure;
  1439. }
  1440. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1441. //
  1442. // Extract application description and name table
  1443. //
  1444. if ((hResultCode = DNReceiveConnectInfo(pdnObject,pvData,pConnection,&dpnid)) != DPN_OK)
  1445. {
  1446. DPFERR("Could not extract name table passed by host");
  1447. DisplayDNError(0,hResultCode);
  1448. goto Failure;
  1449. }
  1450. //
  1451. // Get Connection object for local player
  1452. //
  1453. if ((hResultCode = ConnectionNew(pdnObject,&pLocalConnection)) != DPN_OK)
  1454. {
  1455. DPFERR("Could not create new Connection");
  1456. DisplayDNError(0,hResultCode);
  1457. DNASSERT(FALSE);
  1458. goto Failure;
  1459. }
  1460. //
  1461. // Get Host and Local players
  1462. //
  1463. if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) != DPN_OK)
  1464. {
  1465. DPFERR("Could not find Host player");
  1466. DisplayDNError(0,hResultCode);
  1467. goto Failure;
  1468. }
  1469. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  1470. {
  1471. DPFERR("Could not find Local player");
  1472. DisplayDNError(0,hResultCode);
  1473. goto Failure;
  1474. }
  1475. //
  1476. // Ensure we have an address for the Host player
  1477. //
  1478. if (pHostPlayer->GetAddress() == NULL)
  1479. {
  1480. //
  1481. // Use connect address if it exists
  1482. //
  1483. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1484. if (pdnObject->pConnectAddress)
  1485. {
  1486. IDirectPlay8Address_AddRef(pdnObject->pConnectAddress);
  1487. pIHost = pdnObject->pConnectAddress;
  1488. }
  1489. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1490. if (pIHost == NULL)
  1491. {
  1492. //
  1493. // No connect address was specified, so we will query for the host's address
  1494. //
  1495. if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
  1496. {
  1497. DPFERR("Could not get end point from connection");
  1498. DisplayDNError(0,hResultCode);
  1499. DNASSERT(FALSE);
  1500. goto Failure;
  1501. }
  1502. hResultCode = DNGetClearAddress(pdnObject,hEndPt,&pIHost,TRUE);
  1503. pConnection->ReleaseEndPt(&CallbackThread);
  1504. if (hResultCode != DPN_OK)
  1505. {
  1506. DPFERR("Could not get clear address for Host player");
  1507. DisplayDNError(0,hResultCode);
  1508. DNASSERT(FALSE);
  1509. goto Failure;
  1510. }
  1511. }
  1512. pHostPlayer->SetAddress(pIHost);
  1513. IDirectPlay8Address_Release(pIHost);
  1514. pIHost = NULL;
  1515. }
  1516. //
  1517. // Start LISTENs for CONNECTs from existing players in Peer-Peer mode
  1518. //
  1519. if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  1520. {
  1521. if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
  1522. {
  1523. DPFERR("Could not get end point from connection");
  1524. DisplayDNError(0,hResultCode);
  1525. DNASSERT(FALSE);
  1526. goto Failure;
  1527. }
  1528. hResultCode = DNGetLocalDeviceAddress(pdnObject,hEndPt,&pIDevice);
  1529. pConnection->ReleaseEndPt(&CallbackThread);
  1530. if (hResultCode != DPN_OK)
  1531. {
  1532. DPFERR("Could not get LISTEN address from endpoint");
  1533. DisplayDNError(0,hResultCode);
  1534. DNASSERT(FALSE);
  1535. goto Failure;
  1536. }
  1537. // Parent Async Op
  1538. if ((hResultCode = AsyncOpNew(pdnObject,&pListenParent)) != DPN_OK)
  1539. {
  1540. DPFERR("Could not create AsyncOp");
  1541. DisplayDNError(0,hResultCode);
  1542. DNASSERT(FALSE);
  1543. goto Failure;
  1544. }
  1545. pListenParent->SetOpType( ASYNC_OP_LISTEN );
  1546. pListenParent->MakeParent();
  1547. pListenParent->SetCompletion( DNCompleteListen );
  1548. dwFlags = DN_LISTENFLAGS_DISALLOWENUMS;
  1549. if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0)
  1550. {
  1551. dwFlags |= DN_LISTENFLAGS_SESSIONDATA;
  1552. }
  1553. if (pdnObject->ApplicationDesc.IsFastSigned())
  1554. {
  1555. dwFlags|=DN_LISTENFLAGS_FASTSIGNED;
  1556. }
  1557. else if (pdnObject->ApplicationDesc.IsFullSigned())
  1558. {
  1559. dwFlags|=DN_LISTENFLAGS_FULLSIGNED;
  1560. }
  1561. pListenParent->SetOpFlags( dwFlags );
  1562. // Perform child LISTEN
  1563. hResultCode = DNPerformSPListen(pdnObject,
  1564. pIDevice,
  1565. pListenParent,
  1566. NULL);
  1567. if (hResultCode != DPN_OK)
  1568. {
  1569. DPFERR("Could not perform child LISTEN");
  1570. DisplayDNError(0,hResultCode);
  1571. DNASSERT(FALSE);
  1572. goto Failure;
  1573. }
  1574. // Store parent LISTEN on DirectNet object
  1575. #pragma BUGBUG( minara, "What if we are closing down and have already terminated all listens ?" )
  1576. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1577. pListenParent->AddRef();
  1578. pdnObject->pListenParent = pListenParent;
  1579. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1580. pListenParent->Release();
  1581. pListenParent = NULL;
  1582. IDirectPlay8Address_Release(pIDevice);
  1583. pIDevice = NULL;
  1584. }
  1585. //
  1586. // Indicate peer connected - we will perform this before notifying the host so that
  1587. // DN_OBJECT_FLAG_CONNECTED is set when existing player CONNECTs come in
  1588. //
  1589. if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  1590. {
  1591. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1592. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING))
  1593. {
  1594. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1595. #pragma TODO( minara, "Shut down listen" )
  1596. hResultCode = DPN_OK;
  1597. goto Failure;
  1598. }
  1599. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING);
  1600. pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED;
  1601. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1602. //
  1603. // Inform application of groups and players.
  1604. // We will inform the application of
  1605. // - CREATE_GROUP
  1606. // - ADD_PLAYER (for Local and Host players)
  1607. // - ADD_PLAYER_TO_GROUP
  1608. //
  1609. pdnObject->NameTable.ReadLock();
  1610. pBilink = pdnObject->NameTable.m_bilinkGroups.GetNext();
  1611. while (pBilink != &pdnObject->NameTable.m_bilinkGroups)
  1612. {
  1613. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1614. pNTEntry->AddRef();
  1615. pdnObject->NameTable.Unlock();
  1616. fNotify = FALSE;
  1617. pNTEntry->Lock();
  1618. if (!pNTEntry->IsAvailable() && !pNTEntry->IsDisconnecting() && !pNTEntry->IsAutoDestructGroup())
  1619. {
  1620. pNTEntry->MakeAvailable();
  1621. pNTEntry->NotifyAddRef();
  1622. pNTEntry->NotifyAddRef();
  1623. pNTEntry->SetInUse();
  1624. fNotify = TRUE;
  1625. }
  1626. pNTEntry->Unlock();
  1627. if (fNotify)
  1628. {
  1629. DNASSERT(!pNTEntry->IsAllPlayersGroup());
  1630. DNUserCreateGroup(pdnObject,pNTEntry);
  1631. pNTEntry->PerformQueuedOperations();
  1632. pdnObject->NameTable.PopulateGroup( pNTEntry );
  1633. }
  1634. pNTEntry->Release();
  1635. pNTEntry = NULL;
  1636. pdnObject->NameTable.ReadLock();
  1637. if (pBilink->IsEmpty())
  1638. {
  1639. pBilink = pdnObject->NameTable.m_bilinkGroups.GetNext();
  1640. }
  1641. else
  1642. {
  1643. pBilink = pBilink->GetNext();
  1644. }
  1645. }
  1646. pNTEntry = NULL;
  1647. pdnObject->NameTable.Unlock();
  1648. }
  1649. //
  1650. // We will pre-set the Host connection, so that any operation from the CREATE_PLAYER notification call-back
  1651. // for the local player will be able to find the Host player's connection (to send messages to). We will
  1652. // not, however, expose the Host player to the user yet.
  1653. //
  1654. pHostPlayer->Lock();
  1655. pHostPlayer->SetConnection( pConnection );
  1656. pHostPlayer->Unlock();
  1657. //
  1658. // Add Local player
  1659. //
  1660. pLocalConnection->SetStatus( CONNECTED );
  1661. pLocalConnection->SetEndPt(NULL);
  1662. pLocalConnection->MakeLocal();
  1663. //
  1664. // Preset player context
  1665. //
  1666. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1667. DNASSERT(pdnObject->pConnectParent);
  1668. if (pdnObject->pConnectParent)
  1669. {
  1670. pdnObject->pConnectParent->AddRef();
  1671. pConnectParent = pdnObject->pConnectParent;
  1672. }
  1673. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1674. if (pConnectParent)
  1675. {
  1676. pConnectParent->Lock();
  1677. if (pConnectParent->GetContext())
  1678. {
  1679. pLocalPlayer->Lock();
  1680. pLocalPlayer->SetContext(pConnectParent->GetContext());
  1681. pLocalPlayer->Unlock();
  1682. }
  1683. pConnectParent->SetResult( DPN_OK );
  1684. pConnectParent->Unlock();
  1685. pConnectParent->Release();
  1686. pConnectParent = NULL;
  1687. }
  1688. #ifndef DPNBUILD_NOSERVER
  1689. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER|DN_OBJECT_FLAG_SERVER))
  1690. #else
  1691. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER))
  1692. #endif // DPNBUILD_NOSERVER
  1693. {
  1694. pdnObject->ApplicationDesc.IncPlayerCount( FALSE );
  1695. pLocalConnection->SetDPNID(pLocalPlayer->GetDPNID());
  1696. pdnObject->NameTable.PopulateConnection(pLocalConnection);
  1697. }
  1698. else
  1699. {
  1700. pLocalPlayer->Lock();
  1701. pLocalPlayer->SetConnection(pLocalConnection);
  1702. pLocalPlayer->StopConnecting();
  1703. pLocalPlayer->MakeAvailable();
  1704. pLocalPlayer->Unlock();
  1705. pdnObject->NameTable.DecOutstandingConnections();
  1706. }
  1707. pLocalConnection->Release();
  1708. pLocalConnection = NULL;
  1709. //
  1710. // Add Host player
  1711. //
  1712. #ifndef DPNBUILD_NOSERVER
  1713. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER|DN_OBJECT_FLAG_SERVER))
  1714. #else
  1715. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER))
  1716. #endif // DPNBUILD_NOSERVER
  1717. {
  1718. pdnObject->ApplicationDesc.IncPlayerCount( FALSE );
  1719. //
  1720. // If we have lost the connection to the host player, we will abort the connect process
  1721. //
  1722. pConnection->Lock();
  1723. if (!pConnection->IsDisconnecting() && !pConnection->IsInvalid())
  1724. {
  1725. pConnection->SetDPNID(pHostPlayer->GetDPNID());
  1726. pConnection->SetStatus( CONNECTED );
  1727. pConnection->Unlock();
  1728. pdnObject->NameTable.PopulateConnection(pConnection);
  1729. }
  1730. else
  1731. {
  1732. pConnection->Unlock();
  1733. DNAbortConnect(pdnObject,DPNERR_CONNECTIONLOST);
  1734. goto Failure;
  1735. }
  1736. }
  1737. else
  1738. {
  1739. pConnection->SetStatus( CONNECTED );
  1740. pHostPlayer->Lock();
  1741. pHostPlayer->StopConnecting();
  1742. //
  1743. // We won't make the host player available until after CONNECT_COMPLETE
  1744. // has been indicated and the callback has returned.
  1745. //
  1746. //pHostPlayer->MakeAvailable();
  1747. pHostPlayer->Unlock();
  1748. pdnObject->NameTable.DecOutstandingConnections();
  1749. }
  1750. pLocalPlayer->Release();
  1751. pLocalPlayer = NULL;
  1752. //
  1753. // Process any nametable operations that might have arrived
  1754. //
  1755. pdnObject->NameTable.ReadLock();
  1756. pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
  1757. while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
  1758. {
  1759. pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
  1760. if ((pNTOp->GetVersion() == (pdnObject->NameTable.GetVersion() + 1))
  1761. && !pNTOp->IsInUse())
  1762. {
  1763. pNTOp->SetInUse();
  1764. pdnObject->NameTable.Unlock();
  1765. hResultCode = DNNTPerformOperation( pdnObject,
  1766. pNTOp->GetMsgId(),
  1767. pNTOp->GetRefCountBuffer()->GetBufferAddress() );
  1768. pdnObject->NameTable.ReadLock();
  1769. }
  1770. else
  1771. {
  1772. //
  1773. // Once we find an operation that we won't perform, there is no point continuing
  1774. //
  1775. break;
  1776. }
  1777. pBilink = pBilink->GetNext();
  1778. }
  1779. pdnObject->NameTable.Unlock();
  1780. //
  1781. // Send connect info acknowledgement to host
  1782. //
  1783. hResultCode = DNSendMessage(pdnObject,
  1784. pConnection,
  1785. DN_MSG_INTERNAL_ACK_CONNECT_INFO,
  1786. pHostPlayer->GetDPNID(),
  1787. NULL,
  1788. 0,
  1789. NULL,
  1790. 0,
  1791. DN_SENDFLAGS_RELIABLE,
  1792. NULL,
  1793. NULL);
  1794. if (hResultCode != DPNERR_PENDING)
  1795. {
  1796. DNAbortConnect(pdnObject,hResultCode);
  1797. goto Failure;
  1798. }
  1799. pHostPlayer->Release();
  1800. pHostPlayer = NULL;
  1801. hResultCode = DPN_OK;
  1802. Exit:
  1803. CallbackThread.Deinitialize();
  1804. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  1805. return(hResultCode);
  1806. Failure:
  1807. if (pHostPlayer)
  1808. {
  1809. pHostPlayer->Release();
  1810. pHostPlayer = NULL;
  1811. }
  1812. if (pLocalPlayer)
  1813. {
  1814. pLocalPlayer->Release();
  1815. pLocalPlayer = NULL;
  1816. }
  1817. if (pLocalConnection)
  1818. {
  1819. pLocalConnection->Release();
  1820. pLocalConnection = NULL;
  1821. }
  1822. if (pIDevice)
  1823. {
  1824. IDirectPlay8Address_Release(pIDevice);
  1825. pIDevice = NULL;
  1826. }
  1827. if (pIHost)
  1828. {
  1829. IDirectPlay8Address_Release(pIHost);
  1830. pIHost = NULL;
  1831. }
  1832. if (pListenParent)
  1833. {
  1834. pListenParent->Release();
  1835. pListenParent = NULL;
  1836. }
  1837. if (pConnectParent)
  1838. {
  1839. pConnectParent->Release();
  1840. pConnectParent = NULL;
  1841. }
  1842. goto Exit;
  1843. }
  1844. // DNConnectToHostFailed
  1845. //
  1846. // Clean up if an attempt to connect to the HostPlayer fails
  1847. #undef DPF_MODNAME
  1848. #define DPF_MODNAME "DNConnectToHostFailed"
  1849. HRESULT DNConnectToHostFailed(DIRECTNETOBJECT *const pdnObject,
  1850. PVOID const pvBuffer,
  1851. const DWORD dwBufferSize,
  1852. CConnection *const pConnection)
  1853. {
  1854. CAsyncOp *pConnectParent;
  1855. HRESULT hResultCode;
  1856. CRefCountBuffer *pRefCountBuffer;
  1857. UNALIGNED DN_INTERNAL_MESSAGE_CONNECT_FAILED *pInfo;
  1858. DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p], dwBufferSize [%ld], pConnection [0x%x]",pvBuffer,dwBufferSize,pConnection);
  1859. DNASSERT(pdnObject != NULL);
  1860. DNASSERT(pvBuffer != NULL || dwBufferSize == 0);
  1861. pRefCountBuffer = NULL;
  1862. pConnectParent = NULL;
  1863. if (pvBuffer != NULL)
  1864. {
  1865. pInfo = static_cast<DN_INTERNAL_MESSAGE_CONNECT_FAILED*>(pvBuffer);
  1866. if ((pInfo->dwReplyOffset != 0) && (pInfo->dwReplySize != 0))
  1867. {
  1868. //
  1869. // Extract reply buffer
  1870. //
  1871. if ((hResultCode = RefCountBufferNew(pdnObject,pInfo->dwReplySize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  1872. {
  1873. DPFERR("Could not create RefCountBuffer - ignore and continue");
  1874. DisplayDNError(0,hResultCode);
  1875. }
  1876. else
  1877. {
  1878. memcpy( pRefCountBuffer->GetBufferAddress(),
  1879. static_cast<BYTE*>(pvBuffer) + pInfo->dwReplyOffset,
  1880. pInfo->dwReplySize );
  1881. }
  1882. }
  1883. //
  1884. // Update connect operation parent with results
  1885. //
  1886. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1887. DNASSERT(pdnObject->pConnectParent);
  1888. if (pdnObject->pConnectParent)
  1889. {
  1890. pdnObject->pConnectParent->Lock();
  1891. pdnObject->pConnectParent->SetResult( pInfo->hResultCode );
  1892. pdnObject->pConnectParent->SetRefCountBuffer( pRefCountBuffer );
  1893. pdnObject->pConnectParent->Unlock();
  1894. }
  1895. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1896. if (pRefCountBuffer)
  1897. {
  1898. pRefCountBuffer->Release();
  1899. pRefCountBuffer = NULL;
  1900. }
  1901. DPFX(DPFPREP, 0,"ConnectToHostFailed: [0x%lx]",pInfo->hResultCode);
  1902. }
  1903. //
  1904. // Release the reference on the connection since we will be dropping the link.
  1905. // We are safe releasing the connection here, since the protocol will prevent
  1906. // the Host's DISCONNECT from being passed up to us until after this thread
  1907. // has returned back down.
  1908. //
  1909. pConnection->Disconnect();
  1910. //
  1911. // Clean up DirectNetObject
  1912. //
  1913. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1914. pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_CONNECTED
  1915. | DN_OBJECT_FLAG_CONNECTING
  1916. | DN_OBJECT_FLAG_HOST_CONNECTED));
  1917. if (pdnObject->pConnectParent)
  1918. {
  1919. pConnectParent = pdnObject->pConnectParent;
  1920. pdnObject->pConnectParent = NULL;
  1921. }
  1922. if( pdnObject->pIDP8ADevice )
  1923. {
  1924. IDirectPlay8Address_Release( pdnObject->pIDP8ADevice );
  1925. pdnObject->pIDP8ADevice = NULL;
  1926. }
  1927. if( pdnObject->pConnectAddress )
  1928. {
  1929. IDirectPlay8Address_Release( pdnObject->pConnectAddress );
  1930. pdnObject->pConnectAddress = NULL;
  1931. }
  1932. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1933. if (pConnectParent)
  1934. {
  1935. pConnectParent->Release();
  1936. pConnectParent = NULL;
  1937. }
  1938. DPFX(DPFPREP, 4,"Returning: DPN_OK");
  1939. return(DPN_OK);
  1940. }
  1941. //
  1942. // DNAbortConnect
  1943. //
  1944. // Abort the CONNECT process by cleaning up the DirectNet object and terminating the session
  1945. //
  1946. #undef DPF_MODNAME
  1947. #define DPF_MODNAME "DNAbortConnect"
  1948. HRESULT DNAbortConnect(DIRECTNETOBJECT *const pdnObject,
  1949. const HRESULT hrConnect)
  1950. {
  1951. HRESULT hResultCode;
  1952. CAsyncOp *pConnectParent;
  1953. DPFX(DPFPREP, 4,"Parameters: hrConnect [0x%lx]",hrConnect);
  1954. DNASSERT(pdnObject != NULL);
  1955. pConnectParent = NULL;
  1956. //
  1957. // Clean up DirectNetObject
  1958. //
  1959. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1960. pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_CONNECTED
  1961. | DN_OBJECT_FLAG_CONNECTING
  1962. | DN_OBJECT_FLAG_HOST_CONNECTED));
  1963. if (pdnObject->pConnectParent)
  1964. {
  1965. pdnObject->pConnectParent->AddRef();
  1966. pConnectParent = pdnObject->pConnectParent;
  1967. }
  1968. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1969. //
  1970. // Set error code on connect operation completion
  1971. //
  1972. if (pConnectParent)
  1973. {
  1974. pConnectParent->Lock();
  1975. pConnectParent->SetResult( hrConnect );
  1976. pConnectParent->Unlock();
  1977. }
  1978. //
  1979. // Shut down
  1980. //
  1981. DNTerminateSession(pdnObject,DPN_OK);
  1982. if (pConnectParent)
  1983. {
  1984. pConnectParent->Release();
  1985. pConnectParent = NULL;
  1986. }
  1987. hResultCode = DPN_OK;
  1988. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  1989. return(hResultCode);
  1990. }
  1991. // Player to player connection occurs at the direction of the host. (Peer-to-peer)
  1992. //
  1993. // Once a NewPlayer has connected to the host,
  1994. // The Host will send the NewPlayer's NameTable entry to all existing players
  1995. // Once the NewPlayer has installed the NameTable, it informs the host
  1996. // The Host will instruct the existing players to connect to the NewPlayer
  1997. //
  1998. // When an existing player establishes a connection with the NewPlayer
  1999. // The existing player send their DNID to the NewPlayer and an ADD_PLAYER to app
  2000. // The NewPlayer activates the connecting (existing) player and sends ADD_PLAYER to app
  2001. //
  2002. // DNPlayerConnect1
  2003. //
  2004. // Receive an existing player's DNID. This is called by the NewPlayer. If valid, send an
  2005. // ADD_PLAYER message to the application
  2006. #undef DPF_MODNAME
  2007. #define DPF_MODNAME "DNPlayerConnect1"
  2008. HRESULT DNPlayerConnect1(DIRECTNETOBJECT *const pdnObject,
  2009. const PVOID pv,
  2010. CConnection *const pConnection)
  2011. {
  2012. HRESULT hResultCode;
  2013. CNameTableEntry *pPlayer;
  2014. UNALIGNED DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID *pSend;
  2015. DPFX(DPFPREP, 4,"Parameters: pv [0x%p], pConnection [0x%p]",pv,pConnection);
  2016. DNASSERT(pdnObject != NULL);
  2017. DNASSERT(pv != NULL);
  2018. DNASSERT(pConnection != NULL);
  2019. pPlayer = NULL;
  2020. pSend = static_cast<DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID*>(pv);
  2021. DNASSERT(pSend->dpnid != 0);
  2022. DPFX(DPFPREP, 5,"Player [0x%lx] has connected",pSend->dpnid);
  2023. if ((hResultCode = pdnObject->NameTable.FindEntry(pSend->dpnid,&pPlayer)) != DPN_OK)
  2024. {
  2025. DPFERR("Could not find connecting player!");
  2026. DisplayDNError(0,hResultCode);
  2027. goto Failure;
  2028. }
  2029. //
  2030. // Increment players in session
  2031. //
  2032. pdnObject->ApplicationDesc.IncPlayerCount( FALSE );
  2033. // Associate DNID with player's connection
  2034. pConnection->Lock();
  2035. pConnection->SetDPNID(pSend->dpnid);
  2036. pConnection->SetStatus( CONNECTED );
  2037. pConnection->Unlock();
  2038. // Populate connection
  2039. pdnObject->NameTable.PopulateConnection(pConnection);
  2040. //
  2041. // Now that this connection is part of a NameTableEntry, remove it from the indicated list
  2042. //
  2043. DNEnterCriticalSection(&pdnObject->csConnectionList);
  2044. if (!pConnection->m_bilinkIndicated.IsEmpty())
  2045. {
  2046. pConnection->Release();
  2047. }
  2048. pConnection->m_bilinkIndicated.RemoveFromList();
  2049. DNLeaveCriticalSection(&pdnObject->csConnectionList);
  2050. pPlayer->Release();
  2051. pPlayer = NULL;
  2052. hResultCode = DPN_OK;
  2053. Exit:
  2054. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  2055. return(hResultCode);
  2056. Failure:
  2057. if (pPlayer)
  2058. {
  2059. pPlayer->Release();
  2060. pPlayer = NULL;
  2061. }
  2062. goto Exit;
  2063. }
  2064. // DNConnectToPeer1
  2065. //
  2066. // Accept the NameTable entry of the NewPlayer from the Host, and add it to the local
  2067. // NameTable. The Host will later provide an INSTRUCT_CONNECT message later.
  2068. #undef DPF_MODNAME
  2069. #define DPF_MODNAME "DNConnectToPeer1"
  2070. HRESULT DNConnectToPeer1(DIRECTNETOBJECT *const pdnObject,
  2071. PVOID const pv)
  2072. {
  2073. HRESULT hResultCode;
  2074. DN_NAMETABLE_ENTRY_INFO *pdnNTEInfo;
  2075. CNameTableEntry *pNTEntry;
  2076. // DWORD dwVersion;
  2077. DPFX(DPFPREP, 4,"Parameters: pv [0x%p]",pv);
  2078. DNASSERT(pdnObject != NULL);
  2079. DNASSERT(pv != NULL);
  2080. pNTEntry = NULL;
  2081. //
  2082. // Create and unpack new entry
  2083. //
  2084. if ((hResultCode = NameTableEntryNew(pdnObject,&pNTEntry)) != DPN_OK)
  2085. {
  2086. DPFERR("Could not create new NameTableEntry");
  2087. DisplayDNError(0,hResultCode);
  2088. DNASSERT(FALSE);
  2089. goto Failure;
  2090. }
  2091. pdnNTEInfo = static_cast<DN_NAMETABLE_ENTRY_INFO*>(pv);
  2092. DPFX(DPFPREP, 5,"New player DNID [0x%lx] - installing NameTable entry",pdnNTEInfo->dpnid);
  2093. DPFX(DPFPREP, 5,"Connecting Player URL [%hs]",static_cast<char*>(pv) + pdnNTEInfo->dwURLOffset);
  2094. if ((hResultCode = pNTEntry->UnpackEntryInfo(pdnNTEInfo,static_cast<BYTE*>(pv))) != DPN_OK)
  2095. {
  2096. DPFERR("Could not unpack NameTableEntry");
  2097. DisplayDNError(0,hResultCode);
  2098. DNASSERT(FALSE);
  2099. goto Failure;
  2100. }
  2101. pNTEntry->StartConnecting();
  2102. //
  2103. // Add entry to NameTable
  2104. //
  2105. if ((hResultCode = pdnObject->NameTable.InsertEntry(pNTEntry)) != DPN_OK)
  2106. {
  2107. DPFERR("Could not insert NameTableEntry into NameTable");
  2108. DisplayDNError(0,hResultCode);
  2109. DNASSERT(FALSE);
  2110. goto Failure;
  2111. }
  2112. //
  2113. // Update NameTableVersion
  2114. //
  2115. pdnObject->NameTable.WriteLock();
  2116. pdnObject->NameTable.SetVersion( pdnNTEInfo->dwVersion );
  2117. pdnObject->NameTable.Unlock();
  2118. pNTEntry->Release();
  2119. pNTEntry = NULL;
  2120. Exit:
  2121. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  2122. return(hResultCode);
  2123. Failure:
  2124. if (pNTEntry)
  2125. {
  2126. pNTEntry->Release();
  2127. pNTEntry = NULL;
  2128. }
  2129. goto Exit;
  2130. }
  2131. // DNConnectToPeer2
  2132. //
  2133. // Perform a connection to the NewPlayer (as instructed by Host).
  2134. // Once this connection has completed (DNConnectToPeer2) send this player's DNID
  2135. #undef DPF_MODNAME
  2136. #define DPF_MODNAME "DNConnectToPeer2"
  2137. HRESULT DNConnectToPeer2(DIRECTNETOBJECT *const pdnObject,
  2138. PVOID const pv)
  2139. {
  2140. HRESULT hResultCode;
  2141. CNameTableEntry *pNTEntry;
  2142. CNameTableEntry *pLocalPlayer;
  2143. UNALIGNED DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT *pInfo;
  2144. CServiceProvider *pSP;
  2145. DPFX(DPFPREP, 4,"Parameters: pv [0x%p]", pv);
  2146. DNASSERT(pdnObject != NULL);
  2147. DNASSERT(pv != NULL);
  2148. pNTEntry = NULL;
  2149. pLocalPlayer = NULL;
  2150. pSP = NULL;
  2151. pInfo = static_cast<DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT*>(pv);
  2152. //
  2153. // Update NameTable version
  2154. //
  2155. pdnObject->NameTable.WriteLock();
  2156. pdnObject->NameTable.SetVersion( pInfo->dwVersion );
  2157. pdnObject->NameTable.Unlock();
  2158. //
  2159. // Determine if this is an instruction to connect to ourselves.
  2160. // If it is, don't do anything other than update the NameTable version
  2161. //
  2162. DPFX(DPFPREP, 5,"Instructed to connect to [0x%lx]",pInfo->dpnid);
  2163. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  2164. {
  2165. DPFERR("Could not get local player reference");
  2166. DisplayDNError(0,hResultCode);
  2167. goto Failure;
  2168. }
  2169. if (pLocalPlayer->GetDPNID() == pInfo->dpnid)
  2170. {
  2171. DPFX(DPFPREP, 5,"Ignoring instruction to connect to self");
  2172. hResultCode = DPN_OK;
  2173. goto Failure;
  2174. }
  2175. if ((hResultCode = pdnObject->NameTable.FindEntry(pInfo->dpnid,&pNTEntry)) != DPN_OK)
  2176. {
  2177. DPFERR("Could not find NameTableEntry");
  2178. DisplayDNError(0,hResultCode);
  2179. DNASSERT(FALSE);
  2180. goto Failure;
  2181. }
  2182. //
  2183. // We will not connect to older players. They will connect to us.
  2184. //
  2185. if (pNTEntry->GetVersion() < pLocalPlayer->GetVersion())
  2186. {
  2187. DPFX(DPFPREP, 5,"Ignoring instruction to connect to older player");
  2188. hResultCode = DPN_OK;
  2189. goto Failure;
  2190. }
  2191. pLocalPlayer->Release();
  2192. pLocalPlayer = NULL;
  2193. //
  2194. // Get SP (cached on DirectNet object from original Connect() to host)
  2195. //
  2196. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2197. if (pdnObject->pConnectSP != NULL)
  2198. {
  2199. pdnObject->pConnectSP->AddRef();
  2200. pSP = pdnObject->pConnectSP;
  2201. }
  2202. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2203. if (pSP == NULL)
  2204. {
  2205. DPFERR("Could not find connect SP on DirectNet object");
  2206. hResultCode = DPNERR_GENERIC;
  2207. goto Failure;
  2208. }
  2209. #ifndef DPNBUILD_ONLYONESP
  2210. //
  2211. // Force the correct service provider into the address.
  2212. //
  2213. GUID guidSP;
  2214. pSP->GetGUID(&guidSP);
  2215. if ((hResultCode = IDirectPlay8Address_SetSP(pNTEntry->GetAddress(), &guidSP)) != DPN_OK)
  2216. {
  2217. DPFERR("Could not force correct service provider into player address");
  2218. DisplayDNError(0,hResultCode);
  2219. DNASSERT(FALSE);
  2220. goto Failure;
  2221. }
  2222. #endif // ! DPNBUILD_ONLYONESP
  2223. // Connect to new player
  2224. DPFX(DPFPREP, 5,"Performing Connect");
  2225. DNASSERT(pdnObject->pIDP8ADevice != NULL);
  2226. hResultCode = DNPerformConnect( pdnObject,
  2227. pNTEntry->GetDPNID(),
  2228. pdnObject->pIDP8ADevice,
  2229. pNTEntry->GetAddress(),
  2230. pSP,
  2231. ((pdnObject->ApplicationDesc.GetReservedDataSize() > 0) ? DN_CONNECTFLAGS_SESSIONDATA : 0),
  2232. NULL);
  2233. if (hResultCode == DPNERR_PENDING)
  2234. {
  2235. hResultCode = DPN_OK;
  2236. }
  2237. pSP->Release();
  2238. pSP = NULL;
  2239. pNTEntry->Release();
  2240. pNTEntry = NULL;
  2241. Exit:
  2242. DNASSERT( pSP == NULL );
  2243. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  2244. return(hResultCode);
  2245. Failure:
  2246. if (pNTEntry)
  2247. {
  2248. pNTEntry->Release();
  2249. pNTEntry = NULL;
  2250. }
  2251. if (pLocalPlayer)
  2252. {
  2253. pLocalPlayer->Release();
  2254. pLocalPlayer = NULL;
  2255. }
  2256. if (pSP)
  2257. {
  2258. pSP->Release();
  2259. pSP = NULL;
  2260. }
  2261. goto Exit;
  2262. }
  2263. // DNConnectToPeer3
  2264. //
  2265. // Finish the connection process to the NewPlayer.
  2266. // Once the connection has completed send this player's DNID to NewPlayer and propegate
  2267. // ADD_PLAYER message
  2268. #undef DPF_MODNAME
  2269. #define DPF_MODNAME "DNConnectToPeer3"
  2270. HRESULT DNConnectToPeer3(DIRECTNETOBJECT *const pdnObject,
  2271. const DPNID dpnid,
  2272. CConnection *const pConnection)
  2273. {
  2274. HRESULT hResultCode;
  2275. CNameTableEntry *pNTEntry;
  2276. CNameTableEntry *pLocalPlayer;
  2277. CRefCountBuffer *pRefCountBuffer;
  2278. DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID *pSend;
  2279. DPFX(DPFPREP, 4,"Parameters: dpnid [0x%lx], pConnection [0x%p]",dpnid,pConnection);
  2280. DNASSERT(dpnid != NULL);
  2281. DNASSERT(pConnection != NULL);
  2282. pLocalPlayer = NULL;
  2283. pNTEntry = NULL;
  2284. pRefCountBuffer = NULL;
  2285. //
  2286. // increment players in session
  2287. //
  2288. pdnObject->ApplicationDesc.IncPlayerCount( FALSE );
  2289. // Associate DNID with player's end point handle
  2290. pConnection->Lock();
  2291. pConnection->SetDPNID(dpnid);
  2292. pConnection->SetStatus( CONNECTED );
  2293. pConnection->Unlock();
  2294. //
  2295. // Get New Players's entry
  2296. //
  2297. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  2298. {
  2299. DPFERR("Could not find new player");
  2300. DisplayDNError(0,hResultCode);
  2301. goto Failure;
  2302. }
  2303. //
  2304. // Get Local player's entry
  2305. //
  2306. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  2307. {
  2308. DPFERR("Could not get local player reference");
  2309. DisplayDNError(0,hResultCode);
  2310. goto Failure;
  2311. }
  2312. // Setup buffer to pass local player's DNID
  2313. hResultCode = RefCountBufferNew(pdnObject,
  2314. sizeof(DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID),
  2315. MemoryBlockAlloc,
  2316. MemoryBlockFree,
  2317. &pRefCountBuffer);
  2318. if (hResultCode != DPN_OK)
  2319. {
  2320. DPFERR("Could not allocate buffer to send connecting player DPNID");
  2321. DisplayDNError(0,hResultCode);
  2322. DNASSERT(FALSE);
  2323. goto Failure;
  2324. }
  2325. pSend = reinterpret_cast<DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID*>(pRefCountBuffer->GetBufferAddress());
  2326. pSend->dpnid = pLocalPlayer->GetDPNID();
  2327. pLocalPlayer->Release();
  2328. pLocalPlayer = NULL;
  2329. // Send player's DNID to new player
  2330. hResultCode = DNSendMessage(pdnObject,
  2331. pConnection,
  2332. DN_MSG_INTERNAL_SEND_PLAYER_DNID,
  2333. dpnid,
  2334. pRefCountBuffer->BufferDescAddress(),
  2335. 1,
  2336. pRefCountBuffer,
  2337. 0,
  2338. DN_SENDFLAGS_RELIABLE,
  2339. NULL,
  2340. NULL);
  2341. if (hResultCode != DPNERR_PENDING)
  2342. {
  2343. DPFERR("Could not send connecting player DPNID");
  2344. DisplayDNError(0,hResultCode);
  2345. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  2346. DNASSERT(FALSE);
  2347. goto Failure;
  2348. }
  2349. // Update NameTableEntry with Connection
  2350. pdnObject->NameTable.PopulateConnection(pConnection);
  2351. pRefCountBuffer->Release();
  2352. pRefCountBuffer = NULL;
  2353. pNTEntry->Release();
  2354. pNTEntry = NULL;
  2355. hResultCode = DPN_OK;
  2356. Exit:
  2357. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  2358. return(hResultCode);
  2359. Failure:
  2360. if (pNTEntry)
  2361. {
  2362. pNTEntry->Release();
  2363. pNTEntry = NULL;
  2364. }
  2365. if (pLocalPlayer)
  2366. {
  2367. pLocalPlayer->Release();
  2368. pLocalPlayer = NULL;
  2369. }
  2370. if (pRefCountBuffer)
  2371. {
  2372. pRefCountBuffer->Release();
  2373. pRefCountBuffer = NULL;
  2374. }
  2375. goto Exit;
  2376. }
  2377. // DNConnectToPeerFailed
  2378. //
  2379. // An existing player could not connect to a NewPlayer.
  2380. // Send a message to the Host player that this connect attempt failed
  2381. #undef DPF_MODNAME
  2382. #define DPF_MODNAME "DNConnectToPeerFailed"
  2383. HRESULT DNConnectToPeerFailed(DIRECTNETOBJECT *const pdnObject,
  2384. const DPNID dpnid)
  2385. {
  2386. HRESULT hResultCode;
  2387. CNameTableEntry *pHost;
  2388. CConnection *pConnection;
  2389. CRefCountBuffer *pRCBuffer;
  2390. DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED *pMsg;
  2391. DPFX(DPFPREP, 4,"Parameters: dpnid [0x%lx]",dpnid);
  2392. DNASSERT(pdnObject != NULL);
  2393. DNASSERT(dpnid != 0);
  2394. pHost = NULL;
  2395. pConnection = NULL;
  2396. pRCBuffer = NULL;
  2397. if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHost )) != DPN_OK)
  2398. {
  2399. DPFERR("Could not get Host player reference");
  2400. DisplayDNError(0,hResultCode);
  2401. goto Failure;
  2402. }
  2403. if ((hResultCode = pHost->GetConnectionRef( &pConnection )) != DPN_OK)
  2404. {
  2405. DPFERR("Could not get Host Connection reference");
  2406. DisplayDNError(0,hResultCode);
  2407. goto Failure;
  2408. }
  2409. //
  2410. // Create message
  2411. //
  2412. hResultCode = RefCountBufferNew(pdnObject,
  2413. sizeof(DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED),
  2414. MemoryBlockAlloc,
  2415. MemoryBlockFree,
  2416. &pRCBuffer);
  2417. if (hResultCode != DPN_OK)
  2418. {
  2419. DPFERR("Could not create RefCountBuffer");
  2420. DisplayDNError(0,hResultCode);
  2421. goto Failure;
  2422. }
  2423. pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED*>(pRCBuffer->GetBufferAddress());
  2424. pMsg->dpnid = dpnid;
  2425. //
  2426. // Send message
  2427. //
  2428. hResultCode = DNSendMessage(pdnObject,
  2429. pConnection,
  2430. DN_MSG_INTERNAL_INSTRUCTED_CONNECT_FAILED,
  2431. pHost->GetDPNID(),
  2432. pRCBuffer->BufferDescAddress(),
  2433. 1,
  2434. pRCBuffer,
  2435. 0,
  2436. DN_SENDFLAGS_RELIABLE,
  2437. NULL,
  2438. NULL);
  2439. if (hResultCode != DPNERR_PENDING)
  2440. {
  2441. DPFERR("Could not send CONNECT_FAILED message - maybe OUR connection is down !");
  2442. DisplayDNError(0,hResultCode);
  2443. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  2444. goto Failure;
  2445. }
  2446. //
  2447. // Clean up
  2448. //
  2449. pHost->Release();
  2450. pHost = NULL;
  2451. pConnection->Release();
  2452. pConnection = NULL;
  2453. pRCBuffer->Release();
  2454. pRCBuffer = NULL;
  2455. hResultCode = DPN_OK;
  2456. Exit:
  2457. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  2458. return(hResultCode);
  2459. Failure:
  2460. if (pHost)
  2461. {
  2462. pHost->Release();
  2463. pHost = NULL;
  2464. }
  2465. if (pConnection)
  2466. {
  2467. pConnection->Release();
  2468. pConnection = NULL;
  2469. }
  2470. if (pRCBuffer)
  2471. {
  2472. pRCBuffer->Release();
  2473. pRCBuffer = NULL;
  2474. }
  2475. goto Exit;
  2476. }
  2477. // DNSendConnectInfo
  2478. //
  2479. // Send connection info to a new player.
  2480. // This is the Host Applcation Description and the NameTable
  2481. // This uses an enumeration buffer.
  2482. // The format of the buffer is:
  2483. // <DN_INTERNAL_MESSAGE_CONNECT_INFO>
  2484. // <DN_APPLICATION_DESC>
  2485. // <DN_NAMETABLE_INFO>
  2486. // <DN_NAMETABLE_ENTRY_INFO>
  2487. // <DN_NAMETABLE_ENTRY_INFO>
  2488. // :
  2489. // <strings and data blocks>
  2490. //
  2491. // DNID dnId DNID of new player
  2492. #undef DPF_MODNAME
  2493. #define DPF_MODNAME "DNSendConnectInfo"
  2494. HRESULT DNSendConnectInfo(DIRECTNETOBJECT *const pdnObject,
  2495. CNameTableEntry *const pNTEntry,
  2496. CConnection *const pConnection,
  2497. void *const pvReplyBuffer,
  2498. const DWORD dwReplyBufferSize)
  2499. {
  2500. HRESULT hResultCode;
  2501. CPackedBuffer packedBuffer;
  2502. CRefCountBuffer *pRefCountBuffer;
  2503. DN_INTERNAL_MESSAGE_CONNECT_INFO *pMsg;
  2504. DPFX(DPFPREP, 6,"Parameters: pNTEntry [0x%p], pConnection [0x%p], pvReplyBuffer [0x%p], dwReplyBufferSize [%ld]",
  2505. pNTEntry,pConnection,pvReplyBuffer,dwReplyBufferSize);
  2506. DNASSERT(pdnObject != NULL);
  2507. DNASSERT(pNTEntry != NULL);
  2508. pRefCountBuffer = NULL;
  2509. //
  2510. // Determine size of message
  2511. //
  2512. packedBuffer.Initialize(NULL,0);
  2513. packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CONNECT_INFO));
  2514. packedBuffer.AddToBack(NULL,dwReplyBufferSize);
  2515. pdnObject->ApplicationDesc.PackInfo(&packedBuffer,
  2516. DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|DN_APPDESCINFO_FLAG_RESERVEDDATA|
  2517. DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  2518. pdnObject->NameTable.PackNameTable(pNTEntry,&packedBuffer);
  2519. //
  2520. // Create buffer
  2521. //
  2522. if ((hResultCode = RefCountBufferNew(pdnObject,packedBuffer.GetSizeRequired(),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  2523. {
  2524. DPFERR("Could not allocate RefCountBuffer");
  2525. DisplayDNError(0,hResultCode);
  2526. DNASSERT(FALSE);
  2527. goto Failure;
  2528. }
  2529. packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
  2530. //
  2531. // Fill in buffer
  2532. //
  2533. pMsg = static_cast<DN_INTERNAL_MESSAGE_CONNECT_INFO*>(packedBuffer.GetHeadAddress());
  2534. if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CONNECT_INFO))) != DPN_OK)
  2535. {
  2536. DPFERR("Could not add CONNECT_INFO struct to packed buffer");
  2537. DisplayDNError(0,hResultCode);
  2538. DNASSERT(FALSE);
  2539. goto Failure;
  2540. }
  2541. if ((pvReplyBuffer) && (dwReplyBufferSize != 0))
  2542. {
  2543. if ((hResultCode = packedBuffer.AddToBack(pvReplyBuffer,dwReplyBufferSize)) != DPN_OK)
  2544. {
  2545. DPFERR("Could not add reply buffer to packed buffer");
  2546. DisplayDNError(0,hResultCode);
  2547. DNASSERT(FALSE);
  2548. goto Failure;
  2549. }
  2550. pMsg->dwReplyOffset = packedBuffer.GetTailOffset();
  2551. pMsg->dwReplySize = dwReplyBufferSize;
  2552. }
  2553. else
  2554. {
  2555. pMsg->dwReplyOffset = 0;
  2556. pMsg->dwReplySize = 0;
  2557. }
  2558. hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer,
  2559. DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|DN_APPDESCINFO_FLAG_RESERVEDDATA|
  2560. DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  2561. if (hResultCode != DPN_OK)
  2562. {
  2563. DPFERR("Could not pack ApplicationDesc");
  2564. DisplayDNError(0,hResultCode);
  2565. DNASSERT(FALSE);
  2566. goto Failure;
  2567. }
  2568. if ((hResultCode = pdnObject->NameTable.PackNameTable(pNTEntry,&packedBuffer)) != DPN_OK)
  2569. {
  2570. DPFERR("Could not pack NameTable");
  2571. DisplayDNError(0,hResultCode);
  2572. DNASSERT(FALSE);
  2573. goto Failure;
  2574. }
  2575. // Send the name table to target
  2576. hResultCode = DNSendMessage(pdnObject,
  2577. pConnection,
  2578. DN_MSG_INTERNAL_SEND_CONNECT_INFO,
  2579. pNTEntry->GetDPNID(),
  2580. pRefCountBuffer->BufferDescAddress(),
  2581. 1,
  2582. pRefCountBuffer,
  2583. 0,
  2584. DN_SENDFLAGS_RELIABLE,
  2585. NULL,
  2586. NULL);
  2587. if (hResultCode != DPNERR_PENDING)
  2588. {
  2589. DPFERR("Could not send connect info to joining player");
  2590. DisplayDNError(0,hResultCode);
  2591. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  2592. // DNASSERT(FALSE);
  2593. goto Failure;
  2594. }
  2595. pRefCountBuffer->Release();
  2596. pRefCountBuffer = NULL;
  2597. hResultCode = DPN_OK;
  2598. Exit:
  2599. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  2600. return(hResultCode);
  2601. Failure:
  2602. if (pRefCountBuffer)
  2603. {
  2604. pRefCountBuffer->Release();
  2605. pRefCountBuffer = NULL;
  2606. }
  2607. goto Exit;
  2608. }
  2609. // DNReceiveConnectInfo
  2610. //
  2611. // Receive connect info from the host/server player.
  2612. // This is the Application Description and the NameTable
  2613. // The name table is in an enum buffer, with relative pointer references which will have
  2614. // to be turned into absolutes. This process requires two passes of the buffer.
  2615. // The first pass will extract PLAYERS, and the second pass will extract groups.
  2616. //
  2617. // PVOID pvNTBuffer Pointer to name table enum buffer
  2618. // DWORD dwNumEntries Number of entries in the name table
  2619. #undef DPF_MODNAME
  2620. #define DPF_MODNAME "DNReceiveConnectInfo"
  2621. HRESULT DNReceiveConnectInfo(DIRECTNETOBJECT *const pdnObject,
  2622. void *const pvBuffer,
  2623. CConnection *const pHostConnection,
  2624. DPNID *const pdpnid)
  2625. {
  2626. HRESULT hResultCode;
  2627. void *pvReplyBuffer;
  2628. DWORD dwReplyBufferSize;
  2629. UNALIGNED DPN_APPLICATION_DESC_INFO *pdnAppDescInfo;
  2630. UNALIGNED DN_NAMETABLE_INFO *pdnNTInfo;
  2631. CRefCountBuffer *pRefCountBuffer;
  2632. CAsyncOp *pConnect;
  2633. UNALIGNED DN_INTERNAL_MESSAGE_CONNECT_INFO *pMsg;
  2634. DPFX(DPFPREP, 6,"Parameters: pvBuffer [0x%p], pHostConnection [0x%p], pdpnid [0x%p]",
  2635. pvBuffer,pHostConnection,pdpnid);
  2636. DNASSERT(pdnObject != NULL);
  2637. DNASSERT(pdpnid != NULL);
  2638. DNASSERT(pvBuffer != NULL);
  2639. DNASSERT(pHostConnection != NULL);
  2640. pRefCountBuffer = NULL;
  2641. pConnect = NULL;
  2642. //
  2643. // Pull fixed structures from front of buffer
  2644. //
  2645. pMsg = static_cast<DN_INTERNAL_MESSAGE_CONNECT_INFO*>(pvBuffer);
  2646. pdnAppDescInfo = reinterpret_cast<DPN_APPLICATION_DESC_INFO*>(pMsg + 1);
  2647. pdnNTInfo = reinterpret_cast<DN_NAMETABLE_INFO*>(pdnAppDescInfo + 1);
  2648. //
  2649. // Extract reply buffer
  2650. //
  2651. dwReplyBufferSize = pMsg->dwReplySize;
  2652. if (dwReplyBufferSize > 0)
  2653. {
  2654. pvReplyBuffer = static_cast<void*>(static_cast<BYTE*>(pvBuffer) + pMsg->dwReplyOffset);
  2655. DPFX(DPFPREP, 7,"Reply Buffer [0x%p] [%ld]",pvReplyBuffer,dwReplyBufferSize);
  2656. if ((hResultCode = RefCountBufferNew(pdnObject,dwReplyBufferSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  2657. {
  2658. DPFERR("Could not create RefCountBuffer");
  2659. DisplayDNError(0,hResultCode);
  2660. DNASSERT(FALSE);
  2661. goto Failure;
  2662. }
  2663. memcpy(pRefCountBuffer->GetBufferAddress(),pvReplyBuffer,dwReplyBufferSize);
  2664. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2665. if (pdnObject->pConnectParent)
  2666. {
  2667. pdnObject->pConnectParent->AddRef();
  2668. pConnect = pdnObject->pConnectParent;
  2669. pConnect->SetRefCountBuffer( pRefCountBuffer );
  2670. }
  2671. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2672. pRefCountBuffer->Release();
  2673. pRefCountBuffer = NULL;
  2674. }
  2675. //
  2676. // Extract Application Description
  2677. //
  2678. DPFX(DPFPREP, 7,"Extracting Application Description");
  2679. hResultCode = pdnObject->ApplicationDesc.UnpackInfo(pdnAppDescInfo,pvBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME |
  2680. DN_APPDESCINFO_FLAG_PASSWORD | DN_APPDESCINFO_FLAG_RESERVEDDATA | DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  2681. if (hResultCode != DPN_OK)
  2682. {
  2683. DPFERR("Could not unpack ApplicationDesc");
  2684. DisplayDNError(0,hResultCode);
  2685. goto Failure;
  2686. }
  2687. //
  2688. // Set player count (Host and LocalPlayer)
  2689. //
  2690. #pragma BUGBUG( minara,"What should happen here ?" )
  2691. // dnAppDesc.dwCurrentPlayers = 2;
  2692. //
  2693. // Extract NameTable
  2694. //
  2695. DPFX(DPFPREP, 7,"Extracting NameTable");
  2696. DPFX(DPFPREP, 7,"Set DPNID mask to [0x%lx]",pdnObject->ApplicationDesc.GetDPNIDMask());
  2697. pdnObject->NameTable.SetDPNIDMask( pdnObject->ApplicationDesc.GetDPNIDMask() );
  2698. if ((hResultCode = pdnObject->NameTable.UnpackNameTableInfo(pdnNTInfo,static_cast<BYTE*>(pvBuffer),pdpnid)) != DPN_OK)
  2699. {
  2700. DPFERR("Could not unpack NameTable");
  2701. DisplayDNError(0,hResultCode);
  2702. goto Failure;
  2703. }
  2704. if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  2705. {
  2706. //
  2707. // Create ALL_PLAYERS group
  2708. //
  2709. CNameTableEntry *pAllPlayersGroup;
  2710. pAllPlayersGroup = NULL;
  2711. if ((hResultCode = NameTableEntryNew(pdnObject,&pAllPlayersGroup)) != DPN_OK)
  2712. {
  2713. DPFERR("Could not create NameTableEntry");
  2714. DisplayDNError(0,hResultCode);
  2715. DNASSERT(FALSE);
  2716. goto Failure;
  2717. }
  2718. pAllPlayersGroup->MakeGroup();
  2719. // This function takes the lock internally
  2720. pdnObject->NameTable.MakeAllPlayersGroup(pAllPlayersGroup);
  2721. pAllPlayersGroup->Release();
  2722. pAllPlayersGroup = NULL;
  2723. DNASSERT(pAllPlayersGroup == NULL);
  2724. }
  2725. if (pConnect)
  2726. {
  2727. pConnect->Release();
  2728. pConnect = NULL;
  2729. }
  2730. Exit:
  2731. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  2732. return(hResultCode);
  2733. Failure:
  2734. if (pRefCountBuffer)
  2735. {
  2736. pRefCountBuffer->Release();
  2737. pRefCountBuffer = NULL;
  2738. }
  2739. if (pConnect)
  2740. {
  2741. pConnect->SetResult( hResultCode ); // Try and salvage something !
  2742. pConnect->Release();
  2743. pConnect = NULL;
  2744. }
  2745. goto Exit;
  2746. }
  2747. #undef DPF_MODNAME
  2748. #define DPF_MODNAME "DNGetClearAddress"
  2749. HRESULT DNGetClearAddress(DIRECTNETOBJECT *const pdnObject,
  2750. const HANDLE hEndPt,
  2751. IDirectPlay8Address **const ppAddress,
  2752. const BOOL fPartner)
  2753. {
  2754. SPGETADDRESSINFODATA spInfoData;
  2755. HRESULT hResultCode;
  2756. #ifdef DBG
  2757. TCHAR DP8ABuffer[512] = {0};
  2758. DWORD DP8ASize;
  2759. #endif // DBG
  2760. DPFX(DPFPREP, 6,"Parameters: hEndPt [0x%p], ppAddress [0x%p], fPartner [%ld]",hEndPt,ppAddress,fPartner);
  2761. DNASSERT(pdnObject != NULL);
  2762. DNASSERT(hEndPt != NULL);
  2763. DNASSERT(ppAddress != NULL);
  2764. if (fPartner)
  2765. {
  2766. spInfoData.Flags = SP_GET_ADDRESS_INFO_REMOTE_HOST;
  2767. }
  2768. else
  2769. {
  2770. spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS;
  2771. }
  2772. hResultCode = DNPCrackEndPointDescriptor(pdnObject->pdnProtocolData,hEndPt,&spInfoData);
  2773. if (hResultCode != DPN_OK)
  2774. {
  2775. DPFERR("Unknown error from DNPCrackEndPointDescriptor");
  2776. DisplayDNError(0,hResultCode);
  2777. DNASSERT(FALSE);
  2778. goto Exit;
  2779. }
  2780. *ppAddress = spInfoData.pAddress;
  2781. spInfoData.pAddress = NULL;
  2782. #ifdef DBG
  2783. if (*ppAddress)
  2784. {
  2785. DP8ASize = 512;
  2786. IDirectPlay8Address_GetURL(*ppAddress,DP8ABuffer,&DP8ASize);
  2787. DPFX(DPFPREP, 5,"Remote Address [%s]",DP8ABuffer);
  2788. }
  2789. #endif // DBG
  2790. hResultCode = DPN_OK;
  2791. Exit:
  2792. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  2793. return(hResultCode);
  2794. }
  2795. #undef DPF_MODNAME
  2796. #define DPF_MODNAME "DNGetLocalDeviceAddress"
  2797. HRESULT DNGetLocalDeviceAddress(DIRECTNETOBJECT *const pdnObject,
  2798. const HANDLE hEndPt,
  2799. IDirectPlay8Address **const ppAddress)
  2800. {
  2801. SPGETADDRESSINFODATA spInfoData;
  2802. HRESULT hResultCode;
  2803. #ifdef DBG
  2804. TCHAR DP8ABuffer[512] = {0};
  2805. DWORD DP8ASize;
  2806. #endif // DBG
  2807. DPFX(DPFPREP, 6,"Parameters: hEndPt [0x%p], ppAddress [0x%p]",hEndPt,ppAddress);
  2808. DNASSERT(pdnObject != NULL);
  2809. DNASSERT(hEndPt != NULL);
  2810. DNASSERT(ppAddress != NULL);
  2811. spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
  2812. hResultCode = DNPCrackEndPointDescriptor(pdnObject->pdnProtocolData,hEndPt,&spInfoData);
  2813. if (hResultCode != DPN_OK)
  2814. {
  2815. DPFERR("Unknown error from DNPCrackEndPointDescriptor");
  2816. DisplayDNError(0,hResultCode);
  2817. DNASSERT(FALSE);
  2818. goto Exit;
  2819. }
  2820. *ppAddress = spInfoData.pAddress;
  2821. spInfoData.pAddress = NULL;
  2822. #ifdef DBG
  2823. if (*ppAddress)
  2824. {
  2825. DP8ASize = 512;
  2826. IDirectPlay8Address_GetURL(*ppAddress,DP8ABuffer,&DP8ASize);
  2827. DPFX(DPFPREP, 7,"Remote Address [%s]",DP8ABuffer);
  2828. }
  2829. #endif // DBG
  2830. hResultCode = DPN_OK;
  2831. Exit:
  2832. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  2833. return(hResultCode);
  2834. }