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.

7123 lines
196 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Common.cpp
  6. * Content: DNET common interface routines
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 07/21/99 mjn Created
  12. * 12/23/99 mjn Hand all NameTable update sends from Host to worker thread
  13. * 12/23/99 mjn Fixed use of Host and AllPlayers short cut pointers
  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 Added Instance GUID generation in DN_Host
  17. * 01/05/00 mjn Return DPNERR_NOINTERFACE if CoCreateInstance fails
  18. * 01/06/00 mjn Moved NameTable stuff to NameTable.h
  19. * 01/07/00 mjn Implemented DNSEND_NOCOPY flag in DN_SendTo
  20. * 01/07/00 mjn Moved Misc Functions to DNMisc.h
  21. * 01/08/00 mjn Implemented GetApplicationDesc
  22. * 01/09/00 mjn Application Description stuff
  23. * 01/10/00 mjn Implemented SetApplicationDesc
  24. * 01/11/00 mjn Use CPackedBuffers instead of DN_ENUM_BUFFER_INFOs
  25. * 01/13/00 mjn Removed DIRECTNETOBJECT from Pack/UnpackApplicationDesc
  26. * 01/14/00 mjn Added pvUserContext to Host API call
  27. * 01/14/00 mjn Removed pvUserContext from DN_NAMETABLE_ENTRY
  28. * 01/15/00 mjn Replaced DN_COUNT_BUFFER with CRefCountBuffer
  29. * 01/16/00 mjn Moved User callback stuff to User.h
  30. * 01/18/00 mjn Implemented DNGROUP_AUTODESTRUCT
  31. * 01/18/00 rmt Added calls into voice layer for Close
  32. * 01/19/00 mjn Replaced DN_SYNC_EVENT with CSyncEvent
  33. * 01/20/00 mjn Clean up NameTable operation list in DN_Close
  34. * 01/23/00 mjn Added DN_DestroyPlayer and DNTerminateSession
  35. * 01/28/00 mjn Added DN_ReturnBuffer
  36. * 02/01/00 mjn Added DN_GetCaps, DN_SetCaps
  37. * 02/01/00 mjn Implement Player/Group context values
  38. * 02/09/00 mjn Implemented DNSEND_COMPLETEONPROCESS
  39. * 02/15/00 mjn Implement INFO flags in SetInfo and return context in GetInfo
  40. * 02/17/00 mjn Implemented GetPlayerContext and GetGroupContext
  41. * 02/17/00 mjn Reordered parameters in EnumServiceProviders,EnumHosts,Connect,Host
  42. * 02/18/00 mjn Converted DNADDRESS to IDirectPlayAddress8
  43. * 03/17/00 rmt Moved caps funcs to caps.h/caps.cpp
  44. * 03/23/00 mjn Set group context through CreateGroup
  45. * mjn Set player context through Host and Connect
  46. * mjn Implemented RegisterLobby()
  47. * 03/24/00 mjn Release SP when EnumHost completes
  48. * 03/25/00 rmt Added call into DPNSVR when host begins
  49. * 04/04/00 rmt Added flag to disable calls to DPNSVR and flag to disable
  50. * parameter validation
  51. * 04/05/00 mjn Fixed DestroyClient API call
  52. * 04/06/00 mjn Added DN_GetHostAddress()
  53. * 04/07/00 mjn Prevent Initialize() API from being called twice
  54. * mjn Ensure Host addresses have SP included
  55. * mjn Fixed DN_GetHostAddress() to get address
  56. * 04/09/00 mjn Convert DN_Host() and DN_Connect() to use CAsyncOp
  57. * 04/10/00 mjn Fixed DN_Close() to use flags
  58. * 04/11/00 mjn Use CAsyncOp for ENUMs
  59. * mjn Moved ProcessEnumQuery and ProcessEnumResponse to EnumHosts.cpp
  60. * mjn DNCancelEnum() uses CAsyncOp
  61. * 04/12/00 mjn DNTerminateSession() cancels outstanding ENUMs
  62. * mjn DN_Close() cancels ENUMs instead of DNTerminateSession
  63. * mjn DN_Close() clears DN_OBJECT_FLAG_DISCONNECTING
  64. * 04/13/00 rmt More parameter validation
  65. * 04/14/00 mjn Default Host SP to Device SP if not specified
  66. * mjn Crack LISTENs in DN_Host for DPNSVR
  67. * 04/16/00 mjn DNSendMessage uses CAsyncOp
  68. * 04/17/00 mjn DNCancelSend() uses CAsyncOp
  69. * 04/17/00 mjn Fixed DN_EnumHosts to use Handle parent and SYNC operation
  70. * mjn DN_Close tries to cancel SENDs and ENUMs
  71. * 04/18/00 mjn CConnection tracks connection status better
  72. * mjn Deinitialize HandleTable, and release addresses in DN_Close
  73. * mjn Fixed DN_GetApplicationDesc to return correct size
  74. * 04/19/00 mjn Changed DN_SendTo to accept a range of DPN_BUFFER_DESCs and a count
  75. * mjn Shut down LISTENs earlier in Close sequence
  76. * 04/20/00 mjn Convert ReceiveBuffers to CAsyncOp and reclaim at Close
  77. * mjn DN_SendTo() may be invoked by IDirectPlay8Client::DN_Send()
  78. * 04/23/00 mjn Added parameter to DNPerformChildSend()
  79. * mjn Reimplemented SEND_COMPLETEONPROCESS
  80. * 04/24/00 mjn Updated Group and Info operations to use CAsyncOp's
  81. * 04/25/00 mjn Added DNCancelConnect to DN_CancelAsyncOperation
  82. * 04/26/00 mjn Fixed DN_GetSendQueueInfo to use CAsyncOp's
  83. * 04/26/00 mjn Removed DN_ASYNC_OP and related functions
  84. * 04/27/00 mjn Cause DN_GetPlayerContext()/DN_GetGroupContext() to fail if disconnecting
  85. * 04/28/00 mjn Allow a NULL Device Address in DN_Connect() - steal SP from Host Address
  86. * mjn Save user connect data to be passed during CONNECT sequence
  87. * mjn Prevent infinite loops in group SENDs
  88. * 05/01/00 rmt Bug #33403 - Require DPNSESSION_CLIENT_SERVER mode in client/server mode
  89. * 05/01/00 mjn Prevent unusable SPs from being enumerated.
  90. * 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer()
  91. * 05/04/00 mjn Clean up address list in DN_Host()
  92. * 05/05/00 mjn Free pvConnectData in DN_Close()
  93. * mjn Fixed leak in DN_GetHostAddress()
  94. * 05/16/00 mjn Force return code from ASYNC DN_SendTo() to return DPNERR_PENDING
  95. * mjn Better locking for User notifications
  96. * 05/30/00 mjn Modified logic for group sends to target connected players only
  97. * mjn ASSERT if operations cannot be cancelled in DN_Close()
  98. * 05/31/00 mjn Added operation specific SYNC flags
  99. * 05/31/00 mjn Prevent ALL_PLAYERS group from being enum'd in DN_EnumClientsAndGroups()
  100. * mjn Skip invalid Host addresses
  101. * 06/05/00 mjn Fixed DN_SendTo to handle some errors gracefully
  102. * 06/19/00 mjn DN_Connect and DN_Host enumerate adapters if ALL_ADAPTERS specified
  103. * 06/20/00 mjn Fixed DN_GetHostAddress() to extract host address from LISTENs
  104. * mjn DOH! Forgot to change a line in DN_Host() so that LISTENs use enum'd adapter rather than ALL_ADAPTER
  105. * 06/22/00 mjn Replace CConnection::MakeConnected() with SetStatus()
  106. * 06/23/00 mjn Removed dwPriority from DN_SendTo()
  107. * 06/24/00 mjn Added parent CONNECT AsyncOp to DN_Connect()
  108. * mjn Return DPNERR_UNINITIALIZED from DN_Close() if not initialized (called twice)
  109. * 06/25/00 mjn Added DNUpdateLobbyStatus(), update status for CONNECTED,DISCONNECTED
  110. * mjn Set DirectNetObject as CONNECTED earlier in DN_Host()
  111. * 06/26/00 mjn Replaced DPNADDCLIENTTOGROUP_SYNC DPNADDPLAYERTOGROUP_SYNC
  112. * mjn Replaced DPNREMOVECLIENTFROMGROUP_SYNC with DPNREMOVEPLAYERFROMGROUP_SYNC
  113. * mjn Fixed for() loop counter problem - nested counters used the same variable - DOH !
  114. * 06/27/00 mjn Allow priorities to be specified to GetSendQueueInfo() API calls
  115. * rmt Added abstraction for COM_Co(Un)Initialize
  116. * mjn Removed ASSERT player not found in DN_GetPlayerContext()
  117. * mjn Added DPNSEND_NONSEQUENTIAL flag to Send/SendTo
  118. * mjn Allow mix-n-match of priorities in GetSendQueueInfo() API call
  119. * 07/02/00 mjn Modified DN_SendTo() to use DNSendGroupMessage()
  120. * 07/06/00 mjn Added missing completions for group sends
  121. * mjn Fixed locking problem in CNameTable::MakeLocalPlayer,MakeHostPlayer,MakeAllPlayersGroup
  122. * mjn Turned DPNSEND_NONSEQUENTIAL flag back on in DN_SendTo()
  123. * mjn Use SP handle instead of interface
  124. * 07/07/00 mjn Cleanup pNewHost on DirectNetObject at close
  125. * 07/08/00 mjn Fixed CAsyncOp to contain m_bilinkParent
  126. * 07/09/00 rmt Bug #38323 - RegisterLobby needs a DPNHANDLE parameter.
  127. * 07/11/00 mjn Added NOLOOPBACK capability to group sends
  128. * mjn Fixed DN_EnumHosts() to handle multiple adapters
  129. * 07/12/00 mjn Copy user data on EnumHosts()
  130. * 07/17/00 mjn Removed redundant SyncEvent->Reset() in DN_Initialize
  131. * mjn Clear DN_OBJECT_FLAG_HOST_CONNECTED in DN_Close()
  132. * mjn Check correct return value of DNSendGroupMessage() in DN_SendTo()
  133. * 07/19/00 aarono Bug#39751 add CancelAsyncOperation flag support.
  134. * 07/20/00 mjn Cleaned up DN_Connect()
  135. * 07/21/00 RichGr IA64: Use %p format specifier for 32/64-bit pointers.
  136. * 07/21/00 mjn Cleaned up DN_Close() to release connection object reference
  137. * 07/23/00 mjn Moved assertion in DN_CanceAsyncOperation
  138. * 07/25/00 mjn Fail DN_EnumHosts() if no valid device adapters exist
  139. * 07/26/00 mjn Fix error codes returned from DN_Connect(),DN_GetSendQueueInfo(),DN_DestroyGroup()
  140. * DN_AddClientToGroup(),DN_RemoveClientFromGroup(),DN_SetGroupInfo()
  141. * DN_GetGroupInfo(),DN_EnumGroupMembers()
  142. * mjn Fix DN_GetApplicationDesc() to always return buffer size
  143. * 07/26/00 mjn Fixed locking problem with CAsyncOp::MakeChild()
  144. * 07/28/00 mjn Revised DN_GetSendQueueInfo() to use queue info on CConnection objects
  145. * mjn Cleaned up DN_GetPlayerContext() and DN_GetGroupContext()
  146. * 07/29/00 mjn Better clean up of pending Connect()'s during Close()
  147. * mjn Check user data size in DN_EnumHosts()
  148. * mjn Added fUseCachedCaps to DN_SPEnsureLoaded()
  149. * 07/30/00 mjn Replaced DN_NAMETABLE_PENDING_OP with CPendingDeletion
  150. * 07/31/00 mjn Added hrReason to DNTerminateSession()
  151. * mjn Added dwDestroyReason to DNHostDisconnect()
  152. * mjn Cleaned up DN_TerminateSession()
  153. * 08/03/00 rmt Bug #41244 - Wrong return codes -- part 2
  154. * 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  155. * 08/05/00 mjn Added pParent to DNSendGroupMessage and DNSendMessage()
  156. * mjn Ensure cancelled operations don't proceed
  157. * mjn Prevent hosting players from calling DN_EnumHosts()
  158. * mjn Generate TERMINATE_SESSION notification for host player
  159. * 08/06/00 mjn Added CWorkerJob
  160. * 08/09/00 mjn Moved no-loop-back test in DN_SendTo()
  161. * 08/15/00 rmt Bug #42506 - DPLAY8: LOBBY: Automatic connection settings not being sent
  162. * 08/15/00 mjn Remapped DPNERR_INVALIDENDPOINT from DPNERR_INVALIDPLAYER to DPNERR_NOCONNECTION in DN_SendTo()
  163. * mjn Addef hProtocol to DNRegisterWithDPNSVR() and removed registration from DN_Host()
  164. * 08/16/00 mjn Return DPNERR_INVALIDHOSTADDRESS from DN_EnumHosts() if host address is invalid
  165. * 08/20/00 mjn Removed fUseCachedCaps from DN_SPEnsureLoaded()
  166. * 08/23/00 mjn Flag DirectNetObject as registered with DPNSVR
  167. * 08/24/00 mjn Replace DN_NAMETABLE_OP with CNameTableOp
  168. * 08/29/00 mjn Remap DPNERR_INVALIDPLAYER to DPNERR_CONNECTIONLOST in DN_SendTo()
  169. * 09/01/00 masonb Modified DN_Close to call CloseHandle on hWorkerThread
  170. * 09/04/00 mjn Added CApplicationDesc
  171. * 09/05/00 mjn Set NameTable DPNID mask when hosting
  172. * 09/06/00 mjn Fixed register with DPNSVR problem
  173. * 09/13/00 rmt Bug #44625 - DPVOICE: Multihomed machines are not always enumerable
  174. * Moved registration for DPNSVR into ListenComplete
  175. * 09/17/00 mjn Split CNameTable.m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups
  176. * 10/11/00 mjn Take locks for CNameTableEntry::PackInfo()
  177. * 10/12/00 mjn Set async handle completion after succeeding in DN_EnumHosts()
  178. * 10/17/00 mjn Fixed clean up for unreachable players
  179. * 11/16/00 mjn Fixed uninitialized variable problem in DN_CancelAsyncOperation()
  180. * 12/11/00 mjn Allow API calls after TERMINATE_SESSION without calling Close() first
  181. * 01/09/01 mjn CancelAsyncOperations() returns DPNERR_CANNOTCANCEL if operation doesn't allow it
  182. * 01/10/01 mjn DN_Connect() cancels ENUMs with DPNERR_CONNECTING
  183. * 01/22/01 mjn Check closing instead of disconnecting in getting player/group context and info
  184. * mjn Fixed debug text
  185. * 02/12/01 mjn GetPlayerContext() and GetGroupContext() return DPNERR_NOTREADY if context not yet set
  186. * 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's
  187. * mjn Use cached enum frame size
  188. * 04/11/01 mjn Save hosting flag for query for addressing when listening
  189. * 05/02/01 vpo Whistler 380319: "DPLAY8: CORE: Starts listening before creating local nametable entry"
  190. * 05/07/01 vpo Whistler 384350: "DPLAY8: CORE: Messages from server can be indicated before connect completes"
  191. * 05/14/01 mjn Fix client error handling when completing connect if server not available
  192. * 05/22/01 mjn Properly set DirectNetObject as CONNECTED for successful client connect
  193. * 06/03/01 mjn Clean up connect parent in DNTerminateSession()
  194. * 06/12/01 mjn Ensure DN_Initialize() returns non-DPN_OK value when creating new CSyncEvent or thread fails
  195. * 06/25/01 mjn Unregister from DPNSVR in DNTerminateSession()
  196. * 07/24/01 mjn Added DPNBUILD_NOPARAMVAL compile flag
  197. *@@END_MSINTERNAL
  198. *
  199. ***************************************************************************/
  200. #include "dncorei.h"
  201. //**********************************************************************
  202. // Constant definitions
  203. //**********************************************************************
  204. //**********************************************************************
  205. // Macro definitions
  206. //**********************************************************************
  207. //**********************************************************************
  208. // Structure definitions
  209. //**********************************************************************
  210. //**********************************************************************
  211. // Variable definitions
  212. //**********************************************************************
  213. //**********************************************************************
  214. // Function prototypes
  215. //**********************************************************************
  216. HRESULT DNGetHostAddressHelper(DIRECTNETOBJECT *pdnObject,
  217. IDirectPlay8Address **const prgpAddress,
  218. DWORD *const pcAddress);
  219. //
  220. // Store the user-supplied message handler and context value for call backs
  221. //
  222. #undef DPF_MODNAME
  223. #define DPF_MODNAME "DN_Initialize"
  224. STDMETHODIMP DN_Initialize(PVOID pInterface,
  225. PVOID const pvUserContext,
  226. const PFNDPNMESSAGEHANDLER pfn,
  227. const DWORD dwFlags)
  228. {
  229. HRESULT hResultCode = DPN_OK;
  230. DIRECTNETOBJECT *pdnObject;
  231. #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
  232. CSyncEvent *pThreadPoolSyncEvent;
  233. #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
  234. CSyncEvent *pProtocolSyncEvent;
  235. BOOL fApplicationDesc;
  236. BOOL fHandleTable;
  237. BOOL fProtocol;
  238. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pvUserContext [0x%p], pfn [0x%p], dwFlags [0x%lx]",
  239. pInterface,pvUserContext,pfn,dwFlags);
  240. #ifndef DPNBUILD_NOPARAMVAL
  241. if( !IsValidDirectPlay8Object( pInterface ) )
  242. {
  243. DPFERR("Invalid object specified" );
  244. DPF_RETURN( DPNERR_INVALIDOBJECT );
  245. }
  246. if( pfn == NULL )
  247. {
  248. DPFERR("You must specify a callback function" );
  249. DPF_RETURN( DPNERR_INVALIDPARAM );
  250. }
  251. if( dwFlags & ~(DPNINITIALIZE_DISABLEPARAMVAL
  252. #ifdef DIRECTPLAYDIRECTX9
  253. | DPNINITIALIZE_HINT_LANSESSION
  254. #endif // DIRECTPLAYDIRECTX9
  255. ) )
  256. {
  257. DPFERR("Invalid flags specified" );
  258. DPF_RETURN( DPNERR_INVALIDFLAGS );
  259. }
  260. #endif // !DPNBUILD_NOPARAMVAL
  261. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  262. DNASSERT(pdnObject != NULL);
  263. // Ensure not already initialized
  264. if (pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)
  265. {
  266. DPFERR("Initialize has already been called" );
  267. DPF_RETURN(DPNERR_ALREADYINITIALIZED);
  268. }
  269. #ifndef DPNBUILD_NOPARAMVAL
  270. // Disable parameter validation flag if DPNINITIALIZE_DISABLEPARAMVAL
  271. // is specified
  272. if( dwFlags & DPNINITIALIZE_DISABLEPARAMVAL )
  273. {
  274. pdnObject->dwFlags &= ~(DN_OBJECT_FLAG_PARAMVALIDATION);
  275. }
  276. #endif // !DPNBUILD_NOPARAMVAL
  277. fApplicationDesc = FALSE;
  278. fHandleTable = FALSE;
  279. fProtocol = FALSE;
  280. pProtocolSyncEvent = NULL;
  281. #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
  282. pThreadPoolSyncEvent = NULL;
  283. #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
  284. //
  285. // Lock DirectNetObject in case someone's trying something funny
  286. //
  287. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  288. //
  289. // Initialize ApplicationDescription
  290. //
  291. if ((hResultCode = pdnObject->ApplicationDesc.Initialize()) != DPN_OK)
  292. {
  293. DPFERR("Could not initialize ApplicationDesc");
  294. DisplayDNError(0,hResultCode);
  295. goto Failure;
  296. }
  297. fApplicationDesc = TRUE;
  298. //
  299. // Initialize HandleTable
  300. //
  301. if ((hResultCode = pdnObject->HandleTable.Initialize()) != DPN_OK)
  302. {
  303. DPFERR("Could not initialize HandleTable");
  304. DisplayDNError(0,hResultCode);
  305. goto Failure;
  306. }
  307. fHandleTable = TRUE;
  308. //
  309. // The threadpool interface always exists for the life of the object.
  310. //
  311. DNASSERT(pdnObject->pIDPThreadPoolWork != NULL);
  312. #ifndef DPNBUILD_ONLYONETHREAD
  313. //
  314. // Have the thread pool object try to start at least one thread. Other
  315. // components may request more, but we just need a single worker.
  316. //
  317. // We'll ignore failure, because we could still operate in DoWork mode even
  318. // when starting the thread fails. It most likely failed because the user
  319. // is in that mode already anyway (DPNERR_ALREADYINITIALIZED).
  320. //
  321. hResultCode = IDirectPlay8ThreadPoolWork_RequestTotalThreadCount(pdnObject->pIDPThreadPoolWork, 1, 0);
  322. if (hResultCode != DPN_OK)
  323. {
  324. if (hResultCode != DPNERR_ALREADYINITIALIZED)
  325. {
  326. DPFX(DPFPREP, 0, "Requesting a single thread failed (err = 0x%lx)!", hResultCode);
  327. }
  328. //
  329. // Continue...
  330. //
  331. }
  332. #endif // ! DPNBUILD_ONLYONETHREAD
  333. //
  334. // Initialize protocol and create shut-down event
  335. //
  336. DNASSERT(pdnObject->lProtocolRefCount == 0);
  337. #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
  338. if ((hResultCode = DNPProtocolInitialize( pdnObject->pdnProtocolData, pdnObject, &g_ProtocolVTBL,
  339. pdnObject->pIDPThreadPoolWork, (dwFlags
  340. #ifdef DIRECTPLAYDIRECTX9
  341. & DPNINITIALIZE_HINT_LANSESSION
  342. #endif // DIRECTPLAYDIRECTX9
  343. ))) != DPN_OK)
  344. {
  345. hResultCode = DPNERR_OUTOFMEMORY;
  346. DPFERR("DNPProtocolInitialize() failed");
  347. DisplayDNError(0,hResultCode);
  348. goto Failure;
  349. }
  350. #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
  351. pdnObject->lProtocolRefCount = 1;
  352. fProtocol = TRUE;
  353. DNASSERT( pdnObject->hProtocolShutdownEvent == NULL );
  354. if ((hResultCode = SyncEventNew(pdnObject,&pProtocolSyncEvent)) != DPN_OK)
  355. {
  356. DPFERR("Could not get protocol shutdown event");
  357. DisplayDNError(0,hResultCode);
  358. goto Failure;
  359. }
  360. #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
  361. if ((hResultCode = SyncEventNew(pdnObject,&pThreadPoolSyncEvent)) != DPN_OK)
  362. {
  363. DPFERR("Could not create threadpool shutdown event");
  364. DisplayDNError(0,hResultCode);
  365. goto Failure;
  366. }
  367. pdnObject->lThreadPoolRefCount = 1;
  368. pdnObject->ThreadPoolShutDownEvent = pThreadPoolSyncEvent;
  369. pThreadPoolSyncEvent = NULL;
  370. #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
  371. pdnObject->hProtocolShutdownEvent = pProtocolSyncEvent;
  372. pProtocolSyncEvent = NULL;
  373. pdnObject->pfnDnUserMessageHandler = pfn;
  374. pdnObject->pvUserContext = pvUserContext;
  375. pdnObject->dwFlags |= DN_OBJECT_FLAG_INITIALIZED;
  376. pdnObject->dwMaxFrameSize = 0;
  377. hResultCode = DPN_OK;
  378. Exit:
  379. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  380. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  381. return(hResultCode);
  382. Failure:
  383. if (fApplicationDesc)
  384. {
  385. pdnObject->ApplicationDesc.Deinitialize();
  386. }
  387. if (fHandleTable)
  388. {
  389. pdnObject->HandleTable.Deinitialize();
  390. }
  391. if (pProtocolSyncEvent)
  392. {
  393. pProtocolSyncEvent->ReturnSelfToPool();
  394. pProtocolSyncEvent = NULL;
  395. }
  396. #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
  397. if (pThreadPoolSyncEvent)
  398. {
  399. pThreadPoolSyncEvent->ReturnSelfToPool();
  400. pThreadPoolSyncEvent = NULL;
  401. }
  402. #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
  403. if (fProtocol)
  404. {
  405. DNProtocolRelease(pdnObject);
  406. }
  407. goto Exit;
  408. }
  409. #undef DPF_MODNAME
  410. #define DPF_MODNAME "DN_Close"
  411. STDMETHODIMP DN_Close(PVOID pInterface,const DWORD dwFlags)
  412. {
  413. HRESULT hResultCode = DPN_OK;
  414. DIRECTNETOBJECT *pdnObject;
  415. CBilink *pBilink;
  416. CAsyncOp *pAsyncOp;
  417. CConnection *pConnection;
  418. CPendingDeletion *pPending;
  419. CServiceProvider *pSP;
  420. BOOL fWaitForEvent;
  421. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dwFlags [0x%lx]",pInterface,dwFlags);
  422. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  423. DNASSERT(pdnObject != NULL);
  424. #ifndef DPNBUILD_NOPARAMVAL
  425. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  426. {
  427. if( !IsValidDirectPlay8Object( pInterface ) )
  428. {
  429. DPFERR("Invalid object specified " );
  430. DPF_RETURN( DPNERR_INVALIDOBJECT );
  431. }
  432. #ifdef DIRECTPLAYDIRECTX9
  433. if( dwFlags & ~(DPNCLOSE_IMMEDIATE) )
  434. #else
  435. if (dwFlags != 0)
  436. #endif
  437. {
  438. DPFERR("Invalid flags");
  439. DPF_RETURN( DPNERR_INVALIDFLAGS );
  440. }
  441. }
  442. #endif // !DPNBUILD_NOPARAMVAL
  443. pAsyncOp = NULL;
  444. pConnection = NULL;
  445. pSP = NULL;
  446. //
  447. // Ensure this isn't being called on a callback thread
  448. //
  449. DNEnterCriticalSection(&pdnObject->csCallbackThreads);
  450. pBilink = pdnObject->m_bilinkCallbackThreads.GetNext();
  451. while (pBilink != &pdnObject->m_bilinkCallbackThreads)
  452. {
  453. if ((CONTAINING_CALLBACKTHREAD(pBilink))->IsCurrentThread())
  454. {
  455. DNLeaveCriticalSection(&pdnObject->csCallbackThreads);
  456. DPFERR("Cannot call Close on a callback thread");
  457. hResultCode = DPNERR_NOTALLOWED;
  458. goto Failure;
  459. }
  460. pBilink = pBilink->GetNext();
  461. }
  462. DNLeaveCriticalSection(&pdnObject->csCallbackThreads);
  463. //
  464. // Flag as closing. Make sure this hasn't already been called.
  465. //
  466. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  467. // Ensure already initialized
  468. if ( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
  469. {
  470. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  471. DPFX(DPFPREP, 1, "Object is not initialized" );
  472. DPF_RETURN(DPNERR_UNINITIALIZED);
  473. }
  474. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)
  475. {
  476. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  477. DPFERR("Already closing" );
  478. hResultCode = DPNERR_ALREADYCLOSING;
  479. goto Failure;
  480. }
  481. pdnObject->dwFlags |= DN_OBJECT_FLAG_CLOSING;
  482. #ifdef DIRECTPLAYDIRECTX9
  483. if (dwFlags & DPNCLOSE_IMMEDIATE)
  484. {
  485. //
  486. // We will set DN_OBJECT_FLAG_CLOSING_IMMEDIATE so that any disconnects from now on will be immediate
  487. //
  488. pdnObject->dwFlags |= DN_OBJECT_FLAG_CLOSING_IMMEDIATE;
  489. }
  490. #endif
  491. if (pdnObject->dwLockCount == 0)
  492. {
  493. fWaitForEvent = FALSE;
  494. }
  495. else
  496. {
  497. fWaitForEvent = TRUE;
  498. }
  499. pdnObject->dwClosingThreadID = GetCurrentThreadId();
  500. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  501. #ifdef DBG
  502. {
  503. CNameTableEntry *pLocalPlayer;
  504. if (pdnObject->NameTable.GetLocalPlayerRef(&pLocalPlayer) == DPN_OK)
  505. {
  506. DPFX(DPFPREP, 0,"Local player was [0x%lx]",pLocalPlayer->GetDPNID());
  507. pLocalPlayer->Release();
  508. }
  509. }
  510. #endif // DBG
  511. //
  512. // If there are operations underway, we will wait for them to complete and release the lock count
  513. //
  514. if (fWaitForEvent)
  515. {
  516. hResultCode = IDirectPlay8ThreadPoolWork_WaitWhileWorking(pdnObject->pIDPThreadPoolWork,
  517. HANDLE_FROM_DNHANDLE(pdnObject->hLockEvent),
  518. 0);
  519. DNASSERT(hResultCode == DPN_OK);
  520. }
  521. //
  522. // Cancel connect
  523. //
  524. DPFX(DPFPREP, 3,"Checking CONNECT");
  525. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  526. pAsyncOp = pdnObject->pConnectParent;
  527. pdnObject->pConnectParent = NULL;
  528. pSP = pdnObject->pConnectSP;
  529. pdnObject->pConnectSP = NULL;
  530. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  531. if (pAsyncOp)
  532. {
  533. pAsyncOp->Lock();
  534. pConnection = pAsyncOp->GetConnection();
  535. pAsyncOp->SetConnection( NULL );
  536. pAsyncOp->Unlock();
  537. DPFX(DPFPREP, 3,"Canceling CONNECT");
  538. hResultCode = DNCancelChildren(pdnObject,pAsyncOp);
  539. DPFX(DPFPREP, 3,"Canceling CONNECT returned [0x%lx]",hResultCode);
  540. pAsyncOp->Release();
  541. pAsyncOp = NULL;
  542. if (pConnection)
  543. {
  544. pConnection->Disconnect();
  545. pConnection->Release();
  546. pConnection = NULL;
  547. }
  548. }
  549. if (pSP)
  550. {
  551. pSP->Release();
  552. pSP = NULL;
  553. }
  554. //
  555. // Remove outstanding ENUMs, SENDs, RECEIVE_BUFFERs
  556. //
  557. DPFX(DPFPREP, 3,"Canceling outstanding operations");
  558. hResultCode = DNCancelActiveCommands(pdnObject,( DN_CANCEL_FLAG_ENUM_QUERY
  559. | DN_CANCEL_FLAG_ENUM_RESPONSE
  560. | DN_CANCEL_FLAG_USER_SEND
  561. | DN_CANCEL_FLAG_INTERNAL_SEND
  562. | DN_CANCEL_FLAG_RECEIVE_BUFFER
  563. #ifndef DPNBUILD_NOMULTICAST
  564. | DN_CANCEL_FLAG_JOIN
  565. #endif // ! DPNBUILD_NOMULTICAST
  566. ),
  567. NULL,
  568. FALSE,
  569. 0);
  570. DPFX(DPFPREP, 3,"Canceling outstanding operations returned [0x%lx]",hResultCode);
  571. //
  572. // Cancel any REQUESTs
  573. //
  574. DPFX(DPFPREP, 3,"Canceling requests");
  575. hResultCode = DNCancelRequestCommands(pdnObject);
  576. DPFX(DPFPREP, 3,"Canceling requests returned [0x%lx]",hResultCode);
  577. #ifndef DPNBUILD_NOMULTICAST
  578. //
  579. // Disconnect from multicast group
  580. //
  581. DPFX(DPFPREP, 3,"Disconnecting from multicast group");
  582. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  583. pBilink = pdnObject->m_bilinkMulticast.GetNext();
  584. while (pBilink != &pdnObject->m_bilinkMulticast)
  585. {
  586. pConnection = CONTAINING_OBJECT(pBilink,CConnection,m_bilinkMulticast);
  587. pConnection->m_bilinkMulticast.RemoveFromList();
  588. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  589. pConnection->Disconnect();
  590. pConnection->Release();
  591. pConnection = NULL;
  592. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  593. pBilink = pdnObject->m_bilinkMulticast.GetNext();
  594. }
  595. if (pdnObject->pMulticastSend)
  596. {
  597. pConnection = pdnObject->pMulticastSend;
  598. pdnObject->pMulticastSend = NULL;
  599. }
  600. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  601. if (pConnection)
  602. {
  603. pConnection->Disconnect();
  604. pConnection->Release();
  605. pConnection = NULL;
  606. }
  607. DNASSERT(pConnection == NULL);
  608. #endif // DPNBUILD_NOMULTICAST
  609. //
  610. // Terminate session. This will remove all players from the NameTable
  611. //
  612. DPFX(DPFPREP, 3,"Terminate Session");
  613. if ((hResultCode = DNTerminateSession(pdnObject,DPN_OK)) != DPN_OK)
  614. {
  615. DPFERR("Could not terminate session");
  616. DisplayDNError(0,hResultCode);
  617. DNASSERT(FALSE);
  618. }
  619. //
  620. // Disconnect any indicated connections
  621. //
  622. DNEnterCriticalSection(&pdnObject->csConnectionList);
  623. while (pdnObject->m_bilinkIndicated.GetNext() != &pdnObject->m_bilinkIndicated)
  624. {
  625. pConnection = CONTAINING_OBJECT(pdnObject->m_bilinkIndicated.GetNext(),CConnection,m_bilinkIndicated);
  626. pConnection->m_bilinkIndicated.RemoveFromList();
  627. DNLeaveCriticalSection(&pdnObject->csConnectionList);
  628. DNASSERT(pConnection->GetDPNID() == 0);
  629. pConnection->Disconnect();
  630. pConnection->Release();
  631. pConnection = NULL;
  632. DNEnterCriticalSection(&pdnObject->csConnectionList);
  633. }
  634. DNLeaveCriticalSection(&pdnObject->csConnectionList);
  635. #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
  636. //
  637. // Release SP's
  638. //
  639. DPFX(DPFPREP, 3,"Releasing SPs");
  640. DN_SPReleaseAll(pdnObject);
  641. #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
  642. //
  643. // Shut down protocol
  644. //
  645. DPFX(DPFPREP, 3,"Shutting down Protocol");
  646. DNProtocolRelease(pdnObject);
  647. pdnObject->hProtocolShutdownEvent->WaitForEvent();
  648. #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
  649. if ((hResultCode = DNPProtocolShutdown(pdnObject->pdnProtocolData)) != DPN_OK)
  650. {
  651. DPFERR("Could not shut down Protocol Layer !");
  652. DisplayDNError(0,hResultCode);
  653. DNASSERT(FALSE);
  654. }
  655. #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
  656. pdnObject->hProtocolShutdownEvent->ReturnSelfToPool();
  657. pdnObject->hProtocolShutdownEvent = NULL;
  658. #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
  659. //
  660. // Wait for thread pool to be done
  661. //
  662. DNThreadPoolRelease(pdnObject);
  663. pdnObject->ThreadPoolShutDownEvent->WaitForEvent();
  664. pdnObject->ThreadPoolShutDownEvent->ReturnSelfToPool();
  665. pdnObject->ThreadPoolShutDownEvent = NULL;
  666. #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
  667. //
  668. // The threadpool interface always exists for the life of the object.
  669. //
  670. DNASSERT(pdnObject->pIDPThreadPoolWork != NULL);
  671. //
  672. // Deinitialize HandleTable
  673. //
  674. DPFX(DPFPREP, 3,"Deinitializing HandleTable");
  675. pdnObject->HandleTable.Deinitialize();
  676. //
  677. // Reset NameTable
  678. //
  679. DPFX(DPFPREP, 3,"Resetting NameTable");
  680. pdnObject->NameTable.ResetNameTable();
  681. //
  682. // Deinitialize ApplicationDescription
  683. //
  684. DPFX(DPFPREP, 3,"Deinitializing ApplicationDesc");
  685. pdnObject->ApplicationDesc.Deinitialize();
  686. //
  687. // Any pending NameTable operations
  688. //
  689. pBilink = pdnObject->m_bilinkPendingDeletions.GetNext();
  690. while (pBilink != &pdnObject->m_bilinkPendingDeletions)
  691. {
  692. pPending = CONTAINING_OBJECT(pBilink,CPendingDeletion,m_bilinkPendingDeletions);
  693. pBilink = pBilink->GetNext();
  694. pPending->m_bilinkPendingDeletions.RemoveFromList();
  695. pPending->ReturnSelfToPool();
  696. pPending = NULL;
  697. }
  698. //
  699. // Misc Clean Up
  700. //
  701. if (pdnObject->pIDP8ADevice)
  702. {
  703. IDirectPlay8Address_Release(pdnObject->pIDP8ADevice);
  704. pdnObject->pIDP8ADevice = NULL;
  705. }
  706. if (pdnObject->pvConnectData)
  707. {
  708. DNFree(pdnObject->pvConnectData);
  709. pdnObject->pvConnectData = NULL;
  710. pdnObject->dwConnectDataSize = 0;
  711. }
  712. if( pdnObject->pConnectAddress )
  713. {
  714. IDirectPlay8Address_Release( pdnObject->pConnectAddress );
  715. pdnObject->pConnectAddress = NULL;
  716. }
  717. #ifndef DPNBUILD_NOVOICE
  718. if( pdnObject->pTargetList )
  719. {
  720. delete [] pdnObject->pTargetList;
  721. pdnObject->pTargetList = NULL;
  722. }
  723. if( pdnObject->pExpandedTargetList )
  724. {
  725. delete [] pdnObject->pExpandedTargetList;
  726. pdnObject->pExpandedTargetList = NULL;
  727. }
  728. #endif // !DPNBUILD_NOVOICE
  729. #ifndef DPNBUILD_NOLOBBY
  730. pdnObject->dpnhLobbyConnection = NULL;
  731. // Release our hold on the lobbiedapplication
  732. if( pdnObject->pIDP8LobbiedApplication)
  733. {
  734. IDirectPlay8LobbiedApplication_Release(pdnObject->pIDP8LobbiedApplication);
  735. pdnObject->pIDP8LobbiedApplication = NULL;
  736. }
  737. #endif // ! DPNBUILD_NOLOBBY
  738. //
  739. // Reset DirectNet object flag
  740. //
  741. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  742. pdnObject->dwFlags &= (~( DN_OBJECT_FLAG_INITIALIZED
  743. | DN_OBJECT_FLAG_CLOSING
  744. // | DN_OBJECT_FLAG_DISCONNECTING
  745. // | DN_OBJECT_FLAG_HOST_CONNECTED
  746. | DN_OBJECT_FLAG_LOCALHOST ));
  747. pdnObject->dwMaxFrameSize = 0;
  748. pdnObject->dwClosingThreadID = 0;
  749. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  750. Exit:
  751. DNASSERT( pAsyncOp == NULL );
  752. DNASSERT( pConnection == NULL );
  753. DNASSERT( pSP == NULL );
  754. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  755. return(hResultCode);
  756. Failure:
  757. goto Exit;
  758. }
  759. //
  760. // Enumerate SP's if no SPGUID supplied, or SP Adapters if an SPGUID is supplied
  761. //
  762. #undef DPF_MODNAME
  763. #define DPF_MODNAME "DN_EnumServiceProviders"
  764. STDMETHODIMP DN_EnumServiceProviders( PVOID pInterface,
  765. const GUID *const pguidServiceProvider,
  766. const GUID *const pguidApplication,
  767. DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer,
  768. DWORD *const pcbEnumData,
  769. DWORD *const pcReturned,
  770. const DWORD dwFlags )
  771. {
  772. #if ((defined(DPNBUILD_ONLYONEADAPTER)) || (defined(DPNBUILD_ONLYONESP)))
  773. DPFX(DPFPREP, 0, "Enumerating service providers or their adapters is not supported!");
  774. return DPNERR_UNSUPPORTED;
  775. #else // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONESP
  776. HRESULT hResultCode;
  777. PDIRECTNETOBJECT pdnObject;
  778. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pguidServiceProvider [0x%p], pguidApplication [0x%p], pSPInfoBuffer [0x%p], pcbEnumData [0x%p], pcReturned [0x%p], dwFlags [0x%lx]",
  779. pInterface,pguidServiceProvider,pguidApplication,pSPInfoBuffer,pcbEnumData,pcReturned,dwFlags);
  780. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  781. DNASSERT(pdnObject != NULL);
  782. #ifndef DPNBUILD_NOPARAMVAL
  783. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  784. {
  785. if( FAILED( hResultCode = DN_ValidateEnumServiceProviders( pInterface, pguidServiceProvider, pguidApplication,
  786. pSPInfoBuffer, pcbEnumData, pcReturned, dwFlags ) ) )
  787. {
  788. DPFERR( "Error validating params" );
  789. DPF_RETURN(hResultCode);
  790. }
  791. }
  792. #endif // DPNBUILD_NOPARAMVAL
  793. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
  794. {
  795. DPFERR( "Object is not initialized" );
  796. DPF_RETURN( DPNERR_UNINITIALIZED );
  797. }
  798. if (pguidServiceProvider == NULL) // Enumerate all service providers
  799. {
  800. #ifdef DPNBUILD_ONLYONESP
  801. DPFX(DPFPREP, 0, "Enumerating service providers not supported!");
  802. hResultCode = DPNERR_UNSUPPORTED;
  803. #else // ! DPNBUILD_ONLYONESP
  804. hResultCode = DN_EnumSP( pdnObject,
  805. dwFlags,
  806. #ifndef DPNBUILD_LIBINTERFACE
  807. pguidApplication,
  808. #endif // ! DPNBUILD_LIBINTERFACE
  809. pSPInfoBuffer,
  810. pcbEnumData,
  811. pcReturned);
  812. #endif // ! DPNBUILD_ONLYONESP
  813. }
  814. else // Service provider specified - enumerate adaptors
  815. {
  816. #ifdef DPNBUILD_ONLYONEADAPTER
  817. DPFX(DPFPREP, 0, "Enumerating devices not supported!");
  818. hResultCode = DPNERR_UNSUPPORTED;
  819. #else // ! DPNBUILD_ONLYONEADAPTER
  820. hResultCode = DN_EnumAdapters( pdnObject,
  821. dwFlags,
  822. pguidServiceProvider,
  823. #ifndef DPNBUILD_LIBINTERFACE
  824. pguidApplication,
  825. #endif // ! DPNBUILD_LIBINTERFACE
  826. pSPInfoBuffer,
  827. pcbEnumData,
  828. pcReturned);
  829. #endif // ! DPNBUILD_ONLYONEADAPTER
  830. }
  831. DPFX(DPFPREP, 3,"Set: *pcbEnumData [%ld], *pcReturned [%ld]",*pcbEnumData,*pcReturned);
  832. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  833. return(hResultCode);
  834. #endif // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONESP
  835. }
  836. //
  837. // Cancel an outstanding Async Operation. hAsyncHandle is the operation handle returned when
  838. // the operation was initiated.
  839. //
  840. #undef DPF_MODNAME
  841. #define DPF_MODNAME "DN_CancelAsyncOperation"
  842. STDMETHODIMP DN_CancelAsyncOperation(PVOID pvInterface,
  843. const DPNHANDLE hAsyncOp,
  844. const DWORD dwFlags)
  845. {
  846. HRESULT hResultCode;
  847. CNameTableEntry *pNTEntry;
  848. CConnection *pConnection;
  849. CAsyncOp *pHandleParent;
  850. CAsyncOp *pAsyncOp;
  851. DIRECTNETOBJECT *pdnObject;
  852. DPFX(DPFPREP, 2,"Parameters: pvInterface [0x%p], hAsyncOp [0x%lx], dwFlags [0x%lx]",
  853. pvInterface,hAsyncOp,dwFlags);
  854. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pvInterface));
  855. DNASSERT(pdnObject != NULL);
  856. #ifndef DPNBUILD_NOPARAMVAL
  857. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  858. {
  859. if( FAILED( hResultCode = DN_ValidateCancelAsyncOperation( pvInterface, hAsyncOp, dwFlags ) ) )
  860. {
  861. DPFERR( "Error validating params" );
  862. DPF_RETURN( hResultCode );
  863. }
  864. }
  865. #endif // !DPNBUILD_NOPARAMVAL
  866. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
  867. {
  868. DPFERR( "Object is not initialized" );
  869. DPF_RETURN( DPNERR_UNINITIALIZED );
  870. }
  871. pNTEntry = NULL;
  872. pConnection = NULL;
  873. pAsyncOp = NULL;
  874. pHandleParent = NULL;
  875. //
  876. // If hAsyncOp is specified and it's not supposed to be a player ID, we will cancel the
  877. // operation it represents. Otherwise, we will rely on the flags to determine which operations
  878. // to cancel.
  879. //
  880. if ((hAsyncOp) && (! (dwFlags & DPNCANCEL_PLAYER_SENDS)))
  881. {
  882. //
  883. // Cancel single operation
  884. //
  885. pdnObject->HandleTable.Lock();
  886. if ((hResultCode = pdnObject->HandleTable.Find(hAsyncOp,(PVOID*)&pHandleParent)) != DPN_OK)
  887. {
  888. pdnObject->HandleTable.Unlock();
  889. DPFERR("Invalid USER Handle specified");
  890. hResultCode = DPNERR_INVALIDHANDLE;
  891. goto Failure;
  892. }
  893. else
  894. {
  895. pHandleParent->AddRef();
  896. pdnObject->HandleTable.Unlock();
  897. }
  898. if ( pHandleParent->GetOpType() != ASYNC_OP_USER_HANDLE )
  899. {
  900. DPFERR("Invalid USER Handle specified");
  901. hResultCode = DPNERR_INVALIDHANDLE;
  902. goto Failure;
  903. }
  904. //
  905. // Some operations may be marked as CANNOT_CANCEL. Return DPNERR_CANNOTCANCEL for these
  906. //
  907. if ( pHandleParent->IsCannotCancel() )
  908. {
  909. DPFERR("Operation not allowed to be cancelled");
  910. hResultCode = DPNERR_CANNOTCANCEL;
  911. goto Failure;
  912. }
  913. hResultCode = DNCancelChildren(pdnObject,pHandleParent);
  914. pHandleParent->Release();
  915. pHandleParent = NULL;
  916. }
  917. else
  918. {
  919. //
  920. // Cancel many operations based on flags
  921. //
  922. DWORD dwInternalFlags;
  923. HRESULT hr;
  924. //
  925. // Re-map flags
  926. //
  927. dwInternalFlags = 0;
  928. if (dwFlags & DPNCANCEL_ALL_OPERATIONS)
  929. {
  930. #ifdef DPNBUILD_NOMULTICAST
  931. dwInternalFlags = ( DN_CANCEL_FLAG_CONNECT | DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND );
  932. #else // ! DPNBUILD_NOMULTICAST
  933. dwInternalFlags = ( DN_CANCEL_FLAG_CONNECT | DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND | DN_CANCEL_FLAG_JOIN );
  934. #endif // ! DPNBUILD_NOMULTICAST
  935. }
  936. else if (dwFlags & DPNCANCEL_CONNECT)
  937. {
  938. dwInternalFlags = DN_CANCEL_FLAG_CONNECT;
  939. }
  940. else if (dwFlags & DPNCANCEL_ENUM)
  941. {
  942. dwInternalFlags = DN_CANCEL_FLAG_ENUM_QUERY;
  943. }
  944. else if (dwFlags & DPNCANCEL_SEND)
  945. {
  946. dwInternalFlags = DN_CANCEL_FLAG_USER_SEND;
  947. }
  948. #ifndef DPNBUILD_NOMULTICAST
  949. else if (dwFlags & DPNCANCEL_JOIN)
  950. {
  951. dwInternalFlags = DN_CANCEL_FLAG_JOIN;
  952. }
  953. #endif // ! DPNBUILD_NOMULTICAST
  954. #ifdef DIRECTPLAYDIRECTX9
  955. else if (dwFlags & DPNCANCEL_PLAYER_SENDS)
  956. {
  957. //
  958. // If the DPNCANCEL_PLAYER_SENDS flag is specified, then hAsyncOp is actually
  959. // a player ID (except Client, where it must be 0, and it means the host player).
  960. //
  961. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT)
  962. {
  963. if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef(&pNTEntry)) != DPN_OK)
  964. {
  965. DPFERR("Unable to find host player");
  966. hResultCode = DPNERR_NOCONNECTION;
  967. goto Failure;
  968. }
  969. }
  970. else
  971. {
  972. if ((hResultCode = pdnObject->NameTable.FindEntry((DPNID) hAsyncOp,&pNTEntry)) != DPN_OK)
  973. {
  974. DPFERR("Unable to find specified player");
  975. hResultCode = DPNERR_INVALIDPLAYER;
  976. goto Failure;
  977. }
  978. if (pNTEntry->IsGroup())
  979. {
  980. DPFERR("Specified ID is not a player");
  981. hResultCode = DPNERR_INVALIDPLAYER;
  982. goto Failure;
  983. }
  984. }
  985. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
  986. {
  987. hResultCode = DPNERR_CONNECTIONLOST;
  988. goto Failure;
  989. }
  990. pNTEntry->Release();
  991. pNTEntry = NULL;
  992. //
  993. // Re-map flags.
  994. //
  995. dwInternalFlags = DN_CANCEL_FLAG_USER_SEND;
  996. if (dwFlags & (DPNCANCEL_PLAYER_SENDS_PRIORITY_HIGH | DPNCANCEL_PLAYER_SENDS_PRIORITY_NORMAL | DPNCANCEL_PLAYER_SENDS_PRIORITY_LOW))
  997. {
  998. if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_HIGH))
  999. {
  1000. dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTHIGHPRI;
  1001. }
  1002. if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_NORMAL))
  1003. {
  1004. dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTNORMALPRI;
  1005. }
  1006. if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_LOW))
  1007. {
  1008. dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTLOWPRI;
  1009. }
  1010. //
  1011. // We should have set at least one of the negation flags.
  1012. //
  1013. DNASSERT(dwInternalFlags & (DN_CANCEL_FLAG_USER_SEND_NOTHIGHPRI | DN_CANCEL_FLAG_USER_SEND_NOTNORMALPRI | DN_CANCEL_FLAG_USER_SEND_NOTLOWPRI));
  1014. }
  1015. }
  1016. #endif
  1017. else
  1018. {
  1019. DNASSERT(FALSE); // Should never get here
  1020. }
  1021. DPFX(DPFPREP, 3,"Re-mapped internal flags [0x%lx]",dwInternalFlags);
  1022. //
  1023. // Pre-set error code
  1024. hResultCode = DPN_OK;
  1025. //
  1026. // To cancel a CONNECT, look at the DirectNetObject
  1027. //
  1028. if (dwInternalFlags & DN_CANCEL_FLAG_CONNECT)
  1029. {
  1030. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1031. if (pdnObject->pConnectParent)
  1032. {
  1033. if (pdnObject->pConnectParent->IsChild())
  1034. {
  1035. DNASSERT(pdnObject->pConnectParent->GetParent() != NULL);
  1036. pdnObject->pConnectParent->GetParent()->AddRef();
  1037. pAsyncOp = pdnObject->pConnectParent->GetParent();
  1038. }
  1039. else
  1040. {
  1041. pdnObject->pConnectParent->AddRef();
  1042. pAsyncOp = pdnObject->pConnectParent;
  1043. }
  1044. }
  1045. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1046. if (pAsyncOp)
  1047. {
  1048. DPFX(DPFPREP, 3,"Canceling CONNECT");
  1049. hr = DNCancelChildren(pdnObject,pAsyncOp);
  1050. if (hr != DPN_OK)
  1051. {
  1052. hResultCode = DPNERR_CANNOTCANCEL;
  1053. DPFX(DPFPREP, 7,"Remapping: [0x%lx] returned by DNCancelChildren to: [0x%lx]",hr, hResultCode);
  1054. }
  1055. pAsyncOp->Release();
  1056. pAsyncOp = NULL;
  1057. }
  1058. }
  1059. //
  1060. // To cancel ENUMs and SENDs, cancel out of the active list
  1061. //
  1062. if (dwInternalFlags & (DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND))
  1063. {
  1064. DPFX(DPFPREP, 3,"Canceling ENUMs or SENDs");
  1065. hr = DNCancelActiveCommands(pdnObject,dwInternalFlags,pConnection,FALSE,0);
  1066. if (hr != DPN_OK)
  1067. {
  1068. hResultCode = DPNERR_CANNOTCANCEL;
  1069. DPFX(DPFPREP, 7,"Remapping: [0x%lx] returned by DNCancelActiveCommands to: [0x%lx]",hr, hResultCode);
  1070. }
  1071. }
  1072. }
  1073. Exit:
  1074. if (pConnection)
  1075. {
  1076. pConnection->Release();
  1077. pConnection = NULL;
  1078. }
  1079. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  1080. return(hResultCode);
  1081. Failure:
  1082. if (pAsyncOp)
  1083. {
  1084. pAsyncOp->Release();
  1085. pAsyncOp = NULL;
  1086. }
  1087. if (pHandleParent)
  1088. {
  1089. pHandleParent->Release();
  1090. pHandleParent = NULL;
  1091. }
  1092. if (pNTEntry)
  1093. {
  1094. pNTEntry->Release();
  1095. pNTEntry = NULL;
  1096. }
  1097. goto Exit;
  1098. }
  1099. #undef DPF_MODNAME
  1100. #define DPF_MODNAME "DN_Connect"
  1101. STDMETHODIMP DN_Connect( PVOID pInterface,
  1102. const DPN_APPLICATION_DESC *const pdnAppDesc,
  1103. IDirectPlay8Address *const pHostAddr,
  1104. IDirectPlay8Address *const pDeviceInfo,
  1105. const DPN_SECURITY_DESC *const pdnSecurity,
  1106. const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
  1107. const void *const pvUserConnectData,
  1108. const DWORD dwUserConnectDataSize,
  1109. void *const pvPlayerContext,
  1110. void *const pvAsyncContext,
  1111. DPNHANDLE *const phAsyncHandle,
  1112. const DWORD dwFlags)
  1113. {
  1114. CAsyncOp *pHandleParent;
  1115. CAsyncOp *pConnectParent;
  1116. CAsyncOp *pAsyncOp;
  1117. HRESULT hResultCode;
  1118. DIRECTNETOBJECT *pdnObject;
  1119. CSyncEvent *pSyncEvent;
  1120. HRESULT volatile hrOperation;
  1121. IDirectPlay8Address *pIHost;
  1122. IDirectPlay8Address *pIDevice;
  1123. IDirectPlay8Address *pIAdapter;
  1124. DWORD dwConnectFlags;
  1125. #ifndef DPNBUILD_ONLYONESP
  1126. GUID guidSP;
  1127. #endif // ! DPNBUILD_ONLYONESP
  1128. #ifndef DPNBUILD_ONLYONEADAPTER
  1129. GUID guidAdapter;
  1130. #endif // ! DPNBUILD_ONLYONEADAPTER
  1131. void *pvConnectData;
  1132. void *pvAdapterBuffer;
  1133. DPN_SP_CAPS dnSPCaps;
  1134. #ifndef DPNBUILD_ONLYONEADAPTER
  1135. BOOL fEnumAdapters;
  1136. #endif // ! DPNBUILD_ONLYONEADAPTER
  1137. CRefCountBuffer *pReply;
  1138. CServiceProvider *pSP;
  1139. DWORD dwMultiplexFlag;
  1140. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnAppDesc [0x%p], pHostAddr [0x%p], pDeviceInfo [0x%p], pdnSecurity [0x%p], pdnCredentials [0x%p], pvUserConnectData [0x%p], dwUserConnectDataSize [%ld], pvPlayerContext [0x%p], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
  1141. pInterface,pdnAppDesc,pHostAddr,pDeviceInfo,pdnSecurity,pdnCredentials,pvUserConnectData,dwUserConnectDataSize,pvPlayerContext,pvAsyncContext,phAsyncHandle,dwFlags);
  1142. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  1143. DNASSERT(pdnObject != NULL);
  1144. #ifndef DPNBUILD_NOPARAMVAL
  1145. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  1146. {
  1147. if( FAILED( hResultCode = DN_ValidateConnect( pInterface, pdnAppDesc, pHostAddr, pDeviceInfo,
  1148. pdnSecurity, pdnCredentials, pvUserConnectData,
  1149. dwUserConnectDataSize,pvPlayerContext,
  1150. pvAsyncContext,phAsyncHandle,dwFlags ) ) )
  1151. {
  1152. DPFERR( "Error validating connect params" );
  1153. DPF_RETURN( hResultCode );
  1154. }
  1155. }
  1156. #endif // !DPNBUILD_NOPARAMVAL
  1157. // Check to ensure message handler registered
  1158. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  1159. {
  1160. DPFERR( "Object is not initialized" );
  1161. DPF_RETURN(DPNERR_UNINITIALIZED);
  1162. }
  1163. // Check to ensure not already connected/connecting
  1164. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING)
  1165. {
  1166. DPFERR( "Object is already connecting" );
  1167. DPF_RETURN(DPNERR_CONNECTING);
  1168. }
  1169. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
  1170. {
  1171. DPFERR( "Object is already connected" );
  1172. DPF_RETURN(DPNERR_ALREADYCONNECTED);
  1173. }
  1174. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING))
  1175. {
  1176. DPFERR( "Object is closing or disconnecting" );
  1177. DPF_RETURN(DPNERR_ALREADYCLOSING);
  1178. }
  1179. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1180. pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTING;
  1181. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1182. // Preset these so that they are properly cleaned up
  1183. pIHost = NULL;
  1184. pIDevice = NULL;
  1185. pIAdapter = NULL;
  1186. pSyncEvent = NULL;
  1187. pHandleParent = NULL;
  1188. pConnectParent = NULL;
  1189. pAsyncOp = NULL;
  1190. pvConnectData = NULL;
  1191. pvAdapterBuffer = NULL;
  1192. hrOperation = DPNERR_GENERIC;
  1193. pReply = NULL;
  1194. pSP = NULL;
  1195. dwMultiplexFlag = 0;
  1196. if ((hResultCode = IDirectPlay8Address_Duplicate(pHostAddr,&pIHost)) != DPN_OK)
  1197. {
  1198. DPFERR("Could not duplicate host address");
  1199. DisplayDNError(0,hResultCode);
  1200. DNASSERT(FALSE);
  1201. goto Failure;
  1202. }
  1203. //
  1204. // Duplicate specified Device Address, or create a blank one if NULL
  1205. //
  1206. if (pDeviceInfo != NULL)
  1207. {
  1208. if ((hResultCode = IDirectPlay8Address_Duplicate(pDeviceInfo,&pIDevice)) != DPN_OK)
  1209. {
  1210. DPFERR("Could not duplicate device info");
  1211. DisplayDNError(0,hResultCode);
  1212. DNASSERT(FALSE);
  1213. goto Failure;
  1214. }
  1215. }
  1216. else
  1217. {
  1218. #ifdef DPNBUILD_LIBINTERFACE
  1219. hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
  1220. reinterpret_cast<void**>(&pIDevice));
  1221. #else // ! DPNBUILD_LIBINTERFACE
  1222. hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
  1223. NULL,
  1224. CLSCTX_INPROC_SERVER,
  1225. IID_IDirectPlay8Address,
  1226. reinterpret_cast<void**>(&pIDevice),
  1227. FALSE);
  1228. #endif // ! DPNBUILD_LIBINTERFACE
  1229. if (hResultCode != S_OK)
  1230. {
  1231. DPFERR("Could not create Device Address");
  1232. DisplayDNError(0,hResultCode);
  1233. DNASSERT(FALSE);
  1234. goto Failure;
  1235. }
  1236. }
  1237. #if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_LIBINTERFACE)))
  1238. DNASSERT(pdnObject->pOnlySP != NULL);
  1239. pdnObject->pOnlySP->AddRef();
  1240. pSP = pdnObject->pOnlySP;
  1241. #else // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
  1242. #ifndef DPNBUILD_ONLYONESP
  1243. //
  1244. // If there is no SP on the device address, then steal it from the Host address
  1245. //
  1246. if ((hResultCode = IDirectPlay8Address_GetSP(pIDevice,&guidSP)) != DPN_OK)
  1247. {
  1248. if ((hResultCode = IDirectPlay8Address_GetSP(pIHost,&guidSP)) != DPN_OK)
  1249. {
  1250. DPFERR("Could not retrieve SP from Host Address");
  1251. DisplayDNError(0,hResultCode);
  1252. goto Failure;
  1253. }
  1254. if ((hResultCode = IDirectPlay8Address_SetSP(pIDevice,&guidSP)) != DPN_OK)
  1255. {
  1256. DPFERR("Could not set SP on Device Address");
  1257. DisplayDNError(0,hResultCode);
  1258. goto Failure;
  1259. }
  1260. }
  1261. #endif // ! DPNBUILD_ONLYONESP
  1262. //
  1263. // Ensure SP is loaded
  1264. //
  1265. hResultCode = DN_SPEnsureLoaded(pdnObject,
  1266. #ifndef DPNBUILD_ONLYONESP
  1267. &guidSP,
  1268. #endif // ! DPNBUILD_ONLYONESP
  1269. #ifndef DPNBUILD_LIBINTERFACE
  1270. NULL,
  1271. #endif // ! DPNBUILD_LIBINTERFACE
  1272. &pSP);
  1273. if (hResultCode != DPN_OK)
  1274. {
  1275. DPFERR("Could not find or load SP");
  1276. DisplayDNError(0,hResultCode);
  1277. goto Failure;
  1278. }
  1279. #endif // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
  1280. //
  1281. // Get SP caps
  1282. //
  1283. if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) != DPN_OK)
  1284. {
  1285. DPFERR("Could not get SP caps");
  1286. DisplayDNError(0,hResultCode);
  1287. goto Failure;
  1288. }
  1289. //
  1290. // Update DirectNet Application Description
  1291. //
  1292. pdnObject->ApplicationDesc.Lock();
  1293. hResultCode = pdnObject->ApplicationDesc.Update(pdnAppDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
  1294. DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA|DN_APPDESCINFO_FLAG_GUIDS);
  1295. pdnObject->ApplicationDesc.Unlock();
  1296. // Connect flags to Protocol
  1297. dwConnectFlags = 0;
  1298. #ifndef DPNBUILD_NOSPUI
  1299. if (dwFlags & DPNCONNECT_OKTOQUERYFORADDRESSING)
  1300. {
  1301. dwConnectFlags |= DN_CONNECTFLAGS_OKTOQUERYFORADDRESSING;
  1302. }
  1303. #endif // ! DPNBUILD_NOSPUI
  1304. if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0)
  1305. {
  1306. dwConnectFlags |= DN_CONNECTFLAGS_SESSIONDATA;
  1307. }
  1308. //
  1309. // Create parent async op, which will be released when the ENTIRE connection is finished
  1310. // including nametable transfer and installation on the local machine
  1311. //
  1312. if ((hResultCode = AsyncOpNew(pdnObject,&pConnectParent)) != DPN_OK)
  1313. {
  1314. DPFERR("Could not create AsyncOp");
  1315. DisplayDNError(0,hResultCode);
  1316. DNASSERT(FALSE);
  1317. goto Failure;
  1318. }
  1319. pConnectParent->SetOpType( ASYNC_OP_CONNECT );
  1320. pConnectParent->MakeParent();
  1321. pConnectParent->SetContext( pvPlayerContext );
  1322. pConnectParent->SetResult( DPNERR_NOCONNECTION );
  1323. pConnectParent->SetCompletion( DNCompleteConnectOperation );
  1324. pConnectParent->SetReserved(1);
  1325. if (dwFlags & DPNCONNECT_SYNC)
  1326. {
  1327. DPFX(DPFPREP, 5,"Sync operation - create sync event");
  1328. if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
  1329. {
  1330. DPFERR("Could not create synchronization event");
  1331. DisplayDNError(0,hResultCode);
  1332. DNASSERT(FALSE);
  1333. goto Failure;
  1334. }
  1335. pConnectParent->SetSyncEvent( pSyncEvent );
  1336. pConnectParent->SetResultPointer( &hrOperation );
  1337. pConnectParent->SetOpData( &pReply );
  1338. }
  1339. else
  1340. {
  1341. DPFX(DPFPREP, 5,"Async operation - create handle parent");
  1342. if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK)
  1343. {
  1344. DPFERR("Could not create handle parent");
  1345. DisplayDNError(0,hResultCode);
  1346. DNASSERT(FALSE);
  1347. goto Failure;
  1348. }
  1349. pHandleParent->SetContext( pvAsyncContext );
  1350. pHandleParent->Lock();
  1351. if (pHandleParent->IsCancelled())
  1352. {
  1353. pHandleParent->Unlock();
  1354. pConnectParent->SetResult( DPNERR_USERCANCEL );
  1355. hResultCode = DPNERR_USERCANCEL;
  1356. goto Failure;
  1357. }
  1358. pConnectParent->MakeChild( pHandleParent );
  1359. pHandleParent->Unlock();
  1360. }
  1361. //
  1362. // We will need a parent op for the CONNECTs to help with clean up when the initial CONNECT stage is done
  1363. //
  1364. if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
  1365. {
  1366. DPFERR("Could not create CONNECT parent");
  1367. DisplayDNError(0,hResultCode);
  1368. DNASSERT(FALSE);
  1369. goto Failure;
  1370. }
  1371. pAsyncOp->SetOpType( ASYNC_OP_CONNECT );
  1372. pAsyncOp->MakeParent();
  1373. pAsyncOp->SetResult( DPNERR_NOCONNECTION );
  1374. pAsyncOp->SetCompletion( DNCompleteConnectToHost );
  1375. pAsyncOp->SetOpFlags( dwConnectFlags );
  1376. pConnectParent->Lock();
  1377. if (pConnectParent->IsCancelled())
  1378. {
  1379. pConnectParent->Unlock();
  1380. pAsyncOp->SetResult( DPNERR_USERCANCEL );
  1381. hResultCode = DPNERR_USERCANCEL;
  1382. goto Failure;
  1383. }
  1384. pAsyncOp->MakeChild( pConnectParent );
  1385. pConnectParent->Unlock();
  1386. //
  1387. // Save CONNECT data (if supplied)
  1388. //
  1389. if (pvUserConnectData && dwUserConnectDataSize)
  1390. {
  1391. if ((pvConnectData = DNMalloc(dwUserConnectDataSize)) == NULL)
  1392. {
  1393. DPFERR("Could not allocate CONNECT data buffer");
  1394. DNASSERT(FALSE);
  1395. hResultCode = DPNERR_OUTOFMEMORY;
  1396. goto Failure;
  1397. }
  1398. memcpy(pvConnectData,pvUserConnectData,dwUserConnectDataSize);
  1399. }
  1400. //
  1401. // Update DirectNet object with relevant data
  1402. //
  1403. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1404. pConnectParent->AddRef();
  1405. pdnObject->pConnectParent = pConnectParent;
  1406. if (pvConnectData)
  1407. {
  1408. if (pdnObject->pvConnectData)
  1409. {
  1410. DNFree(pdnObject->pvConnectData);
  1411. pdnObject->pvConnectData = NULL;
  1412. }
  1413. pdnObject->pvConnectData = pvConnectData;
  1414. pdnObject->dwConnectDataSize = dwUserConnectDataSize;
  1415. }
  1416. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1417. #ifndef DPNBUILD_ONLYONEADAPTER
  1418. //
  1419. // If there is no adapter specified in the device address,
  1420. // we will attempt to CONNECT on each individual adapter if the SP supports it
  1421. //
  1422. fEnumAdapters = FALSE;
  1423. if ((hResultCode = IDirectPlay8Address_GetDevice( pIDevice, &guidAdapter )) != DPN_OK)
  1424. {
  1425. DPFX(DPFPREP,1,"Could not determine adapter");
  1426. DisplayDNError(1,hResultCode);
  1427. if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSALLADAPTERS)
  1428. {
  1429. DPFX(DPFPREP, 3,"SP supports CONNECTing on all adapters");
  1430. fEnumAdapters = TRUE;
  1431. }
  1432. }
  1433. else
  1434. {
  1435. DPFX(DPFPREP, 7, "Device address contained adapter GUID.");
  1436. }
  1437. if(fEnumAdapters)
  1438. {
  1439. DWORD dwNumAdapters;
  1440. GUID *pAdapterList = NULL;
  1441. DN_CONNECT_OP_DATA *pConnectOpData = NULL;
  1442. if ((hResultCode = DNEnumAdapterGuids( pdnObject,
  1443. #ifndef DPNBUILD_ONLYONESP
  1444. &guidSP,
  1445. #endif // ! DPNBUILD_ONLYONESP
  1446. 0,
  1447. &pAdapterList,
  1448. &dwNumAdapters)) != DPN_OK)
  1449. {
  1450. DPFERR("Could not enum adapters for this SP");
  1451. DisplayDNError(0,hResultCode);
  1452. goto Failure;
  1453. }
  1454. if (dwNumAdapters == 0)
  1455. {
  1456. DPFERR("No valid device adapters could be found");
  1457. hResultCode = DPNERR_INVALIDDEVICEADDRESS;
  1458. goto Failure;
  1459. }
  1460. pConnectOpData = pAsyncOp->GetLocalConnectOpData();
  1461. pConnectOpData->dwNumAdapters = dwNumAdapters;
  1462. pConnectOpData->dwCurrentAdapter = 0;
  1463. if (dwNumAdapters > 1)
  1464. {
  1465. dwMultiplexFlag |= DN_CONNECTFLAGS_ADDITIONALMULTIPLEXADAPTERS;
  1466. }
  1467. //
  1468. // Choose first adapter for initial LISTEN call
  1469. //
  1470. if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice,pAdapterList)) != DPN_OK)
  1471. {
  1472. DPFERR("Could not set device adapter");
  1473. DisplayDNError(0,hResultCode);
  1474. MemoryBlockFree(pdnObject,pAdapterList);
  1475. pAdapterList = NULL;
  1476. goto Failure;
  1477. }
  1478. pConnectOpData->dwCurrentAdapter++;
  1479. pAsyncOp->SetOpData( pAdapterList );
  1480. pAdapterList = NULL;
  1481. pConnectOpData = NULL;
  1482. }
  1483. #endif // ! DPNBUILD_ONLYONEADAPTER
  1484. pAsyncOp->SetSP( pSP ); // Set this for DNPerformNextConnect()
  1485. //
  1486. // Save SP for future connects
  1487. //
  1488. pSP->AddRef();
  1489. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1490. if (pdnObject->pConnectSP)
  1491. {
  1492. pdnObject->pConnectSP->Release();
  1493. pdnObject->pConnectSP = NULL;
  1494. }
  1495. pdnObject->pConnectSP = pSP;
  1496. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1497. pdnObject->pConnectAddress = pIHost;
  1498. IDirectPlay8Address_AddRef(pdnObject->pConnectAddress);
  1499. //
  1500. // CONNECT !
  1501. //
  1502. hResultCode = DNPerformConnect( pdnObject,
  1503. NULL,
  1504. pIDevice,
  1505. pIHost,
  1506. pSP,
  1507. pAsyncOp->GetOpFlags() | dwMultiplexFlag,
  1508. pAsyncOp);
  1509. if (hResultCode != DPN_OK)
  1510. {
  1511. DPFERR("Could not connect");
  1512. DisplayDNError(0,hResultCode);
  1513. goto Failure;
  1514. }
  1515. pAsyncOp->Release();
  1516. pAsyncOp = NULL;
  1517. pConnectParent->Release();
  1518. pConnectParent = NULL;
  1519. IDirectPlay8Address_Release(pIHost);
  1520. pIHost = NULL;
  1521. IDirectPlay8Address_Release(pIDevice);
  1522. pIDevice = NULL;
  1523. pSP->Release();
  1524. pSP = NULL;
  1525. if (dwFlags & DPNCONNECT_SYNC)
  1526. {
  1527. CNameTableEntry *pHostPlayer;
  1528. pHostPlayer = NULL;
  1529. if ((hResultCode = pSyncEvent->WaitForEvent()) != DPN_OK)
  1530. {
  1531. DPFERR("DNSyncEventWait() terminated bizarrely");
  1532. DNASSERT(FALSE);
  1533. }
  1534. else
  1535. {
  1536. hResultCode = hrOperation;
  1537. }
  1538. pSyncEvent->ReturnSelfToPool();
  1539. pSyncEvent = NULL;
  1540. //
  1541. // No longer connecting
  1542. //
  1543. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1544. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING);
  1545. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1546. //
  1547. // Clients need to release all sends from the server that were
  1548. // queued once the CONNECT_COMPLETE gets indicated.
  1549. // We prepare to do that now.
  1550. //
  1551. if ((hrOperation == DPN_OK) && (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT))
  1552. {
  1553. if (pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer ) == DPN_OK)
  1554. {
  1555. pHostPlayer->Lock();
  1556. pHostPlayer->MakeAvailable();
  1557. pHostPlayer->NotifyAddRef();
  1558. pHostPlayer->SetInUse();
  1559. pHostPlayer->Unlock();
  1560. //
  1561. // We are now connected
  1562. //
  1563. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1564. pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED;
  1565. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1566. }
  1567. else
  1568. {
  1569. //
  1570. // If we couldn't get a reference on the server (host player),
  1571. // then either the server has disconnected, or we are being shut down.
  1572. // In either case, we should return an error
  1573. //
  1574. DPFX(DPFPREP, 0, "Couldn't get host player reference, failing CONNECT!");
  1575. hrOperation = DPNERR_NOCONNECTION;
  1576. hResultCode = hrOperation;
  1577. if (pReply)
  1578. {
  1579. pReply->Release();
  1580. pReply = NULL;
  1581. }
  1582. }
  1583. }
  1584. else
  1585. {
  1586. //
  1587. // Connect failed, or this is a peer/server interface
  1588. //
  1589. }
  1590. //
  1591. // Generate connect completion
  1592. //
  1593. DNUserConnectComplete(pdnObject,0,NULL,hrOperation,pReply);
  1594. if (pReply)
  1595. {
  1596. pReply->Release();
  1597. pReply = NULL;
  1598. }
  1599. //
  1600. // Cancel ENUMs if the CONNECT succeeded and unload SP's
  1601. //
  1602. if (hrOperation == DPN_OK)
  1603. {
  1604. DNCancelActiveCommands(pdnObject,DN_CANCEL_FLAG_ENUM_QUERY,NULL,TRUE,DPNERR_CONNECTING);
  1605. #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
  1606. DN_SPReleaseAll(pdnObject);
  1607. #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
  1608. //
  1609. // Actually release queued messages if necessary
  1610. //
  1611. if (pHostPlayer != NULL)
  1612. {
  1613. pHostPlayer->PerformQueuedOperations();
  1614. pHostPlayer->Release();
  1615. pHostPlayer = NULL;
  1616. }
  1617. }
  1618. DNASSERT( pHostPlayer == NULL );
  1619. }
  1620. else
  1621. {
  1622. pHandleParent->SetCompletion( DNCompleteUserConnect );
  1623. if (phAsyncHandle)
  1624. {
  1625. *phAsyncHandle = pHandleParent->GetHandle();
  1626. }
  1627. pHandleParent->Release();
  1628. pHandleParent = NULL;
  1629. hResultCode = DPNERR_PENDING;
  1630. }
  1631. Exit:
  1632. DNASSERT( pSP == NULL );
  1633. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  1634. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  1635. return(hResultCode);
  1636. Failure:
  1637. if (pSP)
  1638. {
  1639. pSP->Release();
  1640. pSP = NULL;
  1641. }
  1642. if (pHandleParent)
  1643. {
  1644. pHandleParent->Release();
  1645. pHandleParent = NULL;
  1646. }
  1647. if (pConnectParent)
  1648. {
  1649. if (SUCCEEDED(pdnObject->HandleTable.Destroy( pConnectParent->GetHandle(), NULL )))
  1650. {
  1651. // Release the HandleTable reference
  1652. pConnectParent->Release();
  1653. }
  1654. pConnectParent->Release();
  1655. pConnectParent = NULL;
  1656. }
  1657. if (pAsyncOp)
  1658. {
  1659. pAsyncOp->Release();
  1660. pAsyncOp = NULL;
  1661. }
  1662. if (pIHost)
  1663. {
  1664. IDirectPlay8Address_Release(pIHost);
  1665. pIHost = NULL;
  1666. }
  1667. if (pIDevice)
  1668. {
  1669. IDirectPlay8Address_Release(pIDevice);
  1670. pIDevice = NULL;
  1671. }
  1672. if (pIAdapter)
  1673. {
  1674. IDirectPlay8Address_Release(pIAdapter);
  1675. pIAdapter = NULL;
  1676. }
  1677. if (pSyncEvent)
  1678. {
  1679. pSyncEvent->ReturnSelfToPool();
  1680. pSyncEvent = NULL;
  1681. }
  1682. if (pvAdapterBuffer)
  1683. {
  1684. DNFree(pvAdapterBuffer);
  1685. pvAdapterBuffer = NULL;
  1686. }
  1687. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1688. if (pdnObject->pIDP8ADevice)
  1689. {
  1690. IDirectPlay8Address_Release(pdnObject->pIDP8ADevice);
  1691. pdnObject->pIDP8ADevice = NULL;
  1692. }
  1693. if (pdnObject->pvConnectData)
  1694. {
  1695. DNFree(pdnObject->pvConnectData);
  1696. pdnObject->pvConnectData = NULL;
  1697. pdnObject->dwConnectDataSize = 0;
  1698. }
  1699. if( pdnObject->pConnectAddress )
  1700. {
  1701. IDirectPlay8Address_Release( pdnObject->pConnectAddress );
  1702. pdnObject->pConnectAddress = NULL;
  1703. }
  1704. if (pdnObject->pConnectSP)
  1705. {
  1706. pdnObject->pConnectSP->Release();
  1707. pdnObject->pConnectSP = NULL;
  1708. }
  1709. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING);
  1710. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1711. goto Exit;
  1712. }
  1713. // DN_GetSendQueueInfo
  1714. //
  1715. // Get info about the user send queue.
  1716. // This will find the CConnection for a given player and extract the required queue infor from it.
  1717. #undef DPF_MODNAME
  1718. #define DPF_MODNAME "DN_GetSendQueueInfo"
  1719. STDMETHODIMP DN_GetSendQueueInfo(PVOID pInterface,
  1720. const DPNID dpnid,
  1721. DWORD *const pdwNumMsgs,
  1722. DWORD *const pdwNumBytes,
  1723. const DWORD dwFlags)
  1724. {
  1725. DIRECTNETOBJECT *pdnObject;
  1726. DWORD dwQueueFlags;
  1727. DWORD dwNumMsgs;
  1728. DWORD dwNumBytes;
  1729. CNameTableEntry *pNTEntry;
  1730. CConnection *pConnection;
  1731. HRESULT hResultCode;
  1732. DNASSERT(pInterface != NULL);
  1733. DPFX(DPFPREP, 2,"Parameters : pInterface [0x%p], dpnid [0x%lx], pdwNumMsgs [0x%p], pdwNumBytes [0x%p], dwFlags [0x%lx]",
  1734. pInterface,dpnid,pdwNumMsgs,pdwNumBytes,dwFlags);
  1735. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  1736. DNASSERT(pdnObject != NULL);
  1737. #ifndef DPNBUILD_NOPARAMVAL
  1738. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  1739. {
  1740. HRESULT hrResult;
  1741. if( FAILED( hrResult = DN_ValidateGetSendQueueInfo( pInterface, pdwNumMsgs, pdwNumBytes, dwFlags ) ) )
  1742. {
  1743. DPFERR( "Error validating params" );
  1744. DPF_RETURN( hrResult );
  1745. }
  1746. }
  1747. #endif // !DPNBUILD_NOPARAMVAL
  1748. // Check to ensure message handler registered
  1749. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  1750. {
  1751. DPFERR( "Object is not initialized" );
  1752. DPF_RETURN(DPNERR_UNINITIALIZED);
  1753. }
  1754. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  1755. {
  1756. DPFERR( "Object is already connecting" );
  1757. DPF_RETURN(DPNERR_CONNECTING);
  1758. }
  1759. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED ) )
  1760. {
  1761. DPFERR("Object is not connected" );
  1762. DPF_RETURN(DPNERR_NOCONNECTION);
  1763. }
  1764. pNTEntry = NULL;
  1765. pConnection = NULL;
  1766. //
  1767. // Validate specified player ID and get CConnection
  1768. //
  1769. if((hResultCode = pdnObject->NameTable.FindEntry( dpnid, &pNTEntry )) != DPN_OK)
  1770. {
  1771. DPFX(DPFPREP, 0,"Could not find Player ID [0x%lx] in NameTable", dpnid );
  1772. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  1773. {
  1774. DPFERR("Could not find entry in deleted list either");
  1775. hResultCode = DPNERR_INVALIDPLAYER;
  1776. goto Failure;
  1777. }
  1778. pNTEntry->Release();
  1779. pNTEntry = NULL;
  1780. hResultCode = DPNERR_CONNECTIONLOST;
  1781. goto Failure;
  1782. }
  1783. if (pNTEntry->IsLocal() || pNTEntry->IsGroup())
  1784. {
  1785. hResultCode = DPNERR_INVALIDPLAYER;
  1786. goto Failure;
  1787. }
  1788. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
  1789. {
  1790. hResultCode = DPNERR_CONNECTIONLOST;
  1791. goto Failure;
  1792. }
  1793. pNTEntry->Release();
  1794. pNTEntry = NULL;
  1795. //
  1796. // Determine required queues
  1797. //
  1798. dwQueueFlags = dwFlags & (DPNGETSENDQUEUEINFO_PRIORITY_HIGH | DPNGETSENDQUEUEINFO_PRIORITY_NORMAL | DPNGETSENDQUEUEINFO_PRIORITY_LOW);
  1799. if (dwQueueFlags == 0)
  1800. {
  1801. dwQueueFlags = (DPNGETSENDQUEUEINFO_PRIORITY_HIGH | DPNGETSENDQUEUEINFO_PRIORITY_NORMAL | DPNGETSENDQUEUEINFO_PRIORITY_LOW);
  1802. }
  1803. //
  1804. // Extract required info
  1805. //
  1806. dwNumMsgs = 0;
  1807. dwNumBytes = 0;
  1808. pConnection->Lock();
  1809. if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_HIGH)
  1810. {
  1811. dwNumMsgs += pConnection->GetHighQueueNum();
  1812. dwNumBytes += pConnection->GetHighQueueBytes();
  1813. }
  1814. if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_NORMAL)
  1815. {
  1816. dwNumMsgs += pConnection->GetNormalQueueNum();
  1817. dwNumBytes += pConnection->GetNormalQueueBytes();
  1818. }
  1819. if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_LOW)
  1820. {
  1821. dwNumMsgs += pConnection->GetLowQueueNum();
  1822. dwNumBytes += pConnection->GetLowQueueBytes();
  1823. }
  1824. pConnection->Unlock();
  1825. pConnection->Release();
  1826. pConnection = NULL;
  1827. if (pdwNumMsgs)
  1828. {
  1829. *pdwNumMsgs = dwNumMsgs;
  1830. DPFX(DPFPREP, 3,"Setting: *pdwNumMsgs [%ld]",dwNumMsgs);
  1831. }
  1832. if (pdwNumBytes)
  1833. {
  1834. *pdwNumBytes = dwNumBytes;
  1835. DPFX(DPFPREP, 3,"Setting: *pdwNumBytes [%ld]",dwNumBytes);
  1836. }
  1837. hResultCode = DPN_OK;
  1838. Exit:
  1839. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  1840. return(hResultCode);
  1841. Failure:
  1842. if (pNTEntry)
  1843. {
  1844. pNTEntry->Release();
  1845. pNTEntry = NULL;
  1846. }
  1847. if (pConnection)
  1848. {
  1849. pConnection->Release();
  1850. pConnection = NULL;
  1851. }
  1852. goto Exit;
  1853. }
  1854. #undef DPF_MODNAME
  1855. #define DPF_MODNAME "DN_GetApplicationDesc"
  1856. STDMETHODIMP DN_GetApplicationDesc(PVOID pInterface,
  1857. DPN_APPLICATION_DESC *const pAppDescBuffer,
  1858. DWORD *const pcbDataSize,
  1859. const DWORD dwFlags)
  1860. {
  1861. DIRECTNETOBJECT *pdnObject;
  1862. HRESULT hResultCode;
  1863. CPackedBuffer packedBuffer;
  1864. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pAppDescBuffer [0x%p], pcbDataSize [0x%p], dwFlags [0x%lx]",
  1865. pInterface,pAppDescBuffer,pcbDataSize,dwFlags);
  1866. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  1867. DNASSERT(pdnObject != NULL);
  1868. #ifndef DPNBUILD_NOPARAMVAL
  1869. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  1870. {
  1871. if( FAILED( hResultCode = DN_ValidateGetApplicationDesc( pInterface, pAppDescBuffer, pcbDataSize, dwFlags ) ) )
  1872. {
  1873. DPFERR( "Failed validation getappdesc" );
  1874. DPF_RETURN( hResultCode );
  1875. }
  1876. }
  1877. #endif // !DPNBUILD_NOPARAMVAL
  1878. // Check to ensure message handler registered
  1879. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  1880. {
  1881. DPFERR( "Object is not initialized" );
  1882. DPF_RETURN(DPNERR_UNINITIALIZED);
  1883. }
  1884. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  1885. {
  1886. DPFERR("Object is not connected or hosting" );
  1887. DPF_RETURN(DPNERR_NOCONNECTION);
  1888. }
  1889. //
  1890. // Initialize PackedBuffer
  1891. //
  1892. packedBuffer.Initialize(static_cast<void*>(pAppDescBuffer),*pcbDataSize);
  1893. //
  1894. // Try to pack in the application description.
  1895. // If it won't fit, the required size will be in the PackedBuffer.
  1896. //
  1897. hResultCode = pdnObject->ApplicationDesc.Pack(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
  1898. DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  1899. //
  1900. // Ensure we know what's going on
  1901. //
  1902. if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_BUFFERTOOSMALL))
  1903. {
  1904. DPFERR("Unknown error occurred packing application description");
  1905. DisplayDNError(0,hResultCode);
  1906. hResultCode = DPNERR_GENERIC;
  1907. goto Failure;
  1908. }
  1909. //
  1910. // Size of buffer
  1911. //
  1912. *pcbDataSize = packedBuffer.GetSizeRequired();
  1913. Exit:
  1914. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  1915. return(hResultCode);
  1916. Failure:
  1917. goto Exit;
  1918. }
  1919. #undef DPF_MODNAME
  1920. #define DPF_MODNAME "DN_SetApplicationDesc"
  1921. STDMETHODIMP DN_SetApplicationDesc(PVOID pInterface,
  1922. const DPN_APPLICATION_DESC *const pdnApplicationDesc,
  1923. const DWORD dwFlags)
  1924. {
  1925. DIRECTNETOBJECT *pdnObject;
  1926. HRESULT hResultCode = DPN_OK;
  1927. CRefCountBuffer *pRefCountBuffer;
  1928. CPackedBuffer packedBuffer;
  1929. CWorkerJob *pWorkerJob;
  1930. DWORD dwAppDescInfoSize;
  1931. DWORD dwEnumFrameSize;
  1932. DWORD dwUpdateFlags;
  1933. CNameTableEntry *pNTEntry;
  1934. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnApplicationDesc [0x%p], dwFlags [0x%lx]",
  1935. pInterface,pdnApplicationDesc,dwFlags);
  1936. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  1937. DNASSERT(pdnObject != NULL);
  1938. #ifndef DPNBUILD_NOPARAMVAL
  1939. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  1940. {
  1941. if( FAILED( hResultCode = DN_ValidateSetApplicationDesc( pInterface, pdnApplicationDesc, dwFlags ) ) )
  1942. {
  1943. DPFERR( "Error validating setappdesc params" );
  1944. DPF_RETURN( hResultCode );
  1945. }
  1946. }
  1947. #endif // !DPNBUILD_NOPARAMVAL
  1948. // Check to ensure message handler registered
  1949. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  1950. {
  1951. DPFERR( "Object is not initialized" );
  1952. DPF_RETURN(DPNERR_UNINITIALIZED);
  1953. }
  1954. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  1955. {
  1956. DPFERR( "Object has not yet completed connecting / hosting" );
  1957. DPF_RETURN(DPNERR_CONNECTING);
  1958. }
  1959. if ( !DN_CHECK_LOCALHOST( pdnObject ) )
  1960. {
  1961. DPFERR("Object is not connected or hosting" );
  1962. DPF_RETURN(DPNERR_NOTHOST);
  1963. }
  1964. pNTEntry = NULL;
  1965. pRefCountBuffer = NULL;
  1966. pWorkerJob = NULL;
  1967. //
  1968. // This can only be called by the host
  1969. //
  1970. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pNTEntry )) != DPN_OK)
  1971. {
  1972. DPFERR("Could not get local player");
  1973. hResultCode = DPNERR_NOTHOST;
  1974. goto Failure;
  1975. }
  1976. if (!pNTEntry->IsHost())
  1977. {
  1978. DPFERR("Not Host player");
  1979. hResultCode = DPNERR_NOTHOST;
  1980. goto Failure;
  1981. }
  1982. pNTEntry->Release();
  1983. pNTEntry = NULL;
  1984. //
  1985. // Use cached max enum frame size
  1986. //
  1987. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1988. dwEnumFrameSize = pdnObject->dwMaxFrameSize;
  1989. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1990. DNASSERT( dwEnumFrameSize >= (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)) );
  1991. if (dwEnumFrameSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO) + pdnApplicationDesc->dwApplicationReservedDataSize))
  1992. {
  1993. DPFERR("Not enough room for the application reserved data");
  1994. hResultCode = DPNERR_DATATOOLARGE;
  1995. goto Failure;
  1996. }
  1997. //
  1998. // Update Host player's application desc first
  1999. //
  2000. pdnObject->ApplicationDesc.Lock();
  2001. if (pdnApplicationDesc->dwMaxPlayers > 0)
  2002. {
  2003. if (pdnApplicationDesc->dwMaxPlayers < pdnObject->ApplicationDesc.GetCurrentPlayers())
  2004. {
  2005. DPFERR("Cannot set max players to less than the current number of players");
  2006. pdnObject->ApplicationDesc.Unlock();
  2007. hResultCode = DPNERR_SESSIONFULL;
  2008. goto Failure;
  2009. }
  2010. }
  2011. hResultCode = pdnObject->ApplicationDesc.Update(pdnApplicationDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|
  2012. DN_APPDESCINFO_FLAG_PASSWORD|DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  2013. pdnObject->ApplicationDesc.Unlock();
  2014. if (hResultCode != DPN_OK)
  2015. {
  2016. DPFERR("Could not update Application Desciption");
  2017. DisplayDNError(0,hResultCode);
  2018. goto Failure;
  2019. }
  2020. #ifdef DIRECTPLAYDIRECTX9
  2021. //
  2022. // Update Listen if enums allowed/disallowed
  2023. //
  2024. dwUpdateFlags = 0;
  2025. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2026. if ((pdnObject->dwFlags & DN_OBJECT_FLAG_DISALLOW_ENUMS) && !(pdnApplicationDesc->dwFlags & DPNSESSION_NOENUMS))
  2027. {
  2028. dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS;
  2029. pdnObject->dwFlags &= ~DN_OBJECT_FLAG_DISALLOW_ENUMS;
  2030. }
  2031. else if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_DISALLOW_ENUMS) && (pdnApplicationDesc->dwFlags & DPNSESSION_NOENUMS))
  2032. {
  2033. dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS;
  2034. pdnObject->dwFlags |= DN_OBJECT_FLAG_DISALLOW_ENUMS;
  2035. }
  2036. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2037. if (dwUpdateFlags)
  2038. {
  2039. DNUpdateListens(pdnObject,dwUpdateFlags);
  2040. }
  2041. #endif // DIRECTPLAYDIRECTX9
  2042. //
  2043. // Inform host application
  2044. //
  2045. hResultCode = DNUserUpdateAppDesc(pdnObject);
  2046. //
  2047. // Get Application Description Info size
  2048. //
  2049. packedBuffer.Initialize(NULL,0);
  2050. hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
  2051. DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  2052. DNASSERT(hResultCode == DPNERR_BUFFERTOOSMALL);
  2053. dwAppDescInfoSize = packedBuffer.GetSizeRequired();
  2054. //
  2055. // Create packed buffer to send to other players
  2056. //
  2057. if ((hResultCode = RefCountBufferNew(pdnObject,dwAppDescInfoSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  2058. {
  2059. DPFERR("Could not create CountBuffer");
  2060. DisplayDNError(0,hResultCode);
  2061. goto Failure;
  2062. }
  2063. packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
  2064. hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
  2065. DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  2066. if (hResultCode != DPN_OK)
  2067. {
  2068. DPFERR("Could not pack Application Description into buffer");
  2069. DisplayDNError(0,hResultCode);
  2070. goto Failure;
  2071. }
  2072. //
  2073. // Notify other players
  2074. //
  2075. DPFX(DPFPREP, 5,"Adding UpdateApplicationDesc to Job Queue");
  2076. if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) == DPN_OK)
  2077. {
  2078. pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
  2079. pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_UPDATE_APPLICATION_DESC );
  2080. pWorkerJob->SetSendNameTableOperationVersion( 0 );
  2081. pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
  2082. pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
  2083. DNQueueWorkerJob(pdnObject,pWorkerJob);
  2084. pWorkerJob = NULL;
  2085. }
  2086. else
  2087. {
  2088. DPFERR("Could not create worker job - ignore and continue");
  2089. DisplayDNError(0,hResultCode);
  2090. }
  2091. pRefCountBuffer->Release();
  2092. pRefCountBuffer = NULL;
  2093. hResultCode = DPN_OK;
  2094. Exit:
  2095. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  2096. return(hResultCode);
  2097. Failure:
  2098. if (pNTEntry)
  2099. {
  2100. pNTEntry->Release();
  2101. pNTEntry = NULL;
  2102. }
  2103. if (pRefCountBuffer)
  2104. {
  2105. pRefCountBuffer->Release();
  2106. pRefCountBuffer = NULL;
  2107. }
  2108. goto Exit;
  2109. }
  2110. #undef DPF_MODNAME
  2111. #define DPF_MODNAME "DNTerminateSession"
  2112. HRESULT DNTerminateSession(DIRECTNETOBJECT *const pdnObject,
  2113. const HRESULT hrReason)
  2114. {
  2115. HRESULT hResultCode;
  2116. #ifndef DPNBUILD_NOLOBBY
  2117. BOOL fWasConnected;
  2118. #endif // ! DPNBUILD_NOLOBBY
  2119. #ifndef DPNBUILD_SINGLEPROCESS
  2120. BOOL fWasRegistered;
  2121. #endif // ! DPNBUILD_SINGLEPROCESS
  2122. CAsyncOp *pAsyncOp;
  2123. DPFX(DPFPREP, 4,"Parameters: hrReason [0x%lx]",hrReason);
  2124. DNASSERT(pdnObject != NULL);
  2125. DNASSERT( (hrReason == DPN_OK) || (hrReason == DPNERR_HOSTTERMINATEDSESSION) || (hrReason == DPNERR_CONNECTIONLOST));
  2126. pAsyncOp = NULL;
  2127. //
  2128. // Shut down listen(s)
  2129. //
  2130. DPFX(DPFPREP, 3,"Checking LISTENs");
  2131. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2132. pAsyncOp = pdnObject->pListenParent;
  2133. pdnObject->pListenParent = NULL;
  2134. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2135. if (pAsyncOp)
  2136. {
  2137. DPFX(DPFPREP, 3,"Canceling LISTENs");
  2138. hResultCode = DNCancelChildren(pdnObject,pAsyncOp);
  2139. DPFX(DPFPREP, 3,"Canceling LISTENs returned [0x%lx]",hResultCode);
  2140. pAsyncOp->Release();
  2141. pAsyncOp = NULL;
  2142. }
  2143. #ifndef DPNBUILD_SINGLEPROCESS
  2144. //
  2145. // Unregister from DPNSVR (if required)
  2146. //
  2147. fWasRegistered = FALSE;
  2148. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2149. if (pdnObject->dwFlags & DN_OBJECT_FLAG_DPNSVR_REGISTERED)
  2150. {
  2151. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_DPNSVR_REGISTERED);
  2152. fWasRegistered = TRUE;
  2153. }
  2154. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2155. if (fWasRegistered)
  2156. {
  2157. pdnObject->ApplicationDesc.UnregisterWithDPNSVR();
  2158. }
  2159. #endif // ! DPNBUILD_SINGLEPROCESS
  2160. //
  2161. // Flag DirectNetObject as disconnecting. This flag will be cleared when Close() finishes.
  2162. //
  2163. #ifndef DPNBUILD_NOLOBBY
  2164. fWasConnected = FALSE;
  2165. #endif // ! DPNBUILD_NOLOBBY
  2166. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2167. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
  2168. {
  2169. #ifndef DPNBUILD_NOLOBBY
  2170. fWasConnected = TRUE;
  2171. #endif // ! DPNBUILD_NOLOBBY
  2172. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTED);
  2173. }
  2174. #pragma BUGBUG( minara,"How usefull is this DN_OBJECT_FLAG_DISCONNECTING flag ?" )
  2175. pdnObject->dwFlags |= DN_OBJECT_FLAG_DISCONNECTING;
  2176. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2177. #ifndef DPNBUILD_NOLOBBY
  2178. //
  2179. // Update Lobby status
  2180. //
  2181. if (fWasConnected)
  2182. {
  2183. DNUpdateLobbyStatus(pdnObject,DPLSESSION_DISCONNECTED);
  2184. }
  2185. #endif // ! DPNBUILD_NOLOBBY
  2186. #ifndef DPNBUILD_NOVOICE
  2187. //
  2188. // Notify Voice
  2189. //
  2190. Voice_Notify( pdnObject, DVEVENT_STOPSESSION, 0, 0 );
  2191. #endif // DPNBUILD_NOVOICE
  2192. //
  2193. // Remove host migration target
  2194. //
  2195. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2196. if (pdnObject->pNewHost)
  2197. {
  2198. pdnObject->pNewHost->Release();
  2199. pdnObject->pNewHost = NULL;
  2200. }
  2201. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2202. //
  2203. // Delete all players from NameTable. This will involve
  2204. // emptying the table and removing short-cut player pointers
  2205. //
  2206. DPFX(DPFPREP, 5,"Removing players from NameTable");
  2207. pdnObject->NameTable.EmptyTable(hrReason);
  2208. //
  2209. // Clean up NameTable operation list
  2210. //
  2211. if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  2212. {
  2213. DPFX(DPFPREP, 5,"Cleaning up NameTable operation list");
  2214. DNNTRemoveOperations(pdnObject,0,TRUE);
  2215. }
  2216. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2217. //
  2218. // Clean up CONNECT parent
  2219. //
  2220. if (pdnObject->pConnectParent)
  2221. {
  2222. pAsyncOp = pdnObject->pConnectParent;
  2223. pdnObject->pConnectParent = NULL;
  2224. }
  2225. //
  2226. // Clean up CONNECT info and address
  2227. //
  2228. if (pdnObject->pvConnectData)
  2229. {
  2230. DNFree(pdnObject->pvConnectData);
  2231. pdnObject->pvConnectData = NULL;
  2232. pdnObject->dwConnectDataSize = 0;
  2233. }
  2234. if (pdnObject->pConnectAddress)
  2235. {
  2236. IDirectPlay8Address_Release(pdnObject->pConnectAddress);
  2237. pdnObject->pConnectAddress = NULL;
  2238. }
  2239. if (pdnObject->pIDP8ADevice)
  2240. {
  2241. IDirectPlay8Address_Release(pdnObject->pIDP8ADevice);
  2242. pdnObject->pIDP8ADevice = NULL;
  2243. }
  2244. //
  2245. // Clear the DISCONNECTING and HOST_CONNECTED flag
  2246. // and clear connection info
  2247. //
  2248. pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_DISCONNECTING
  2249. | DN_OBJECT_FLAG_HOST_CONNECTED));
  2250. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2251. if (pAsyncOp)
  2252. {
  2253. pAsyncOp->Release();
  2254. pAsyncOp = NULL;
  2255. }
  2256. hResultCode = DPN_OK;
  2257. DNASSERT(pAsyncOp == NULL);
  2258. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  2259. return(hResultCode);
  2260. }
  2261. #undef DPF_MODNAME
  2262. #define DPF_MODNAME "DN_SendTo"
  2263. STDMETHODIMP DN_SendTo( PVOID pv,
  2264. const DPNID dpnid,
  2265. const DPN_BUFFER_DESC *const prgBufferDesc,
  2266. const DWORD cBufferDesc,
  2267. const DWORD dwTimeOut,
  2268. void *const pvAsyncContext,
  2269. DPNHANDLE *const phAsyncHandle,
  2270. const DWORD dwFlags)
  2271. {
  2272. HRESULT hResultCode;
  2273. HRESULT hrSend;
  2274. CNameTableEntry *pNTEntry;
  2275. CNameTableEntry *pLocalPlayer;
  2276. DIRECTNETOBJECT *pdnObject;
  2277. DWORD dwSendFlags;
  2278. CSyncEvent *pSyncEvent;
  2279. const DPN_BUFFER_DESC *pActualBufferDesc;
  2280. DWORD dwActualBufferDesc;
  2281. CRefCountBuffer *pRefCountBuffer;
  2282. DPNHANDLE handle;
  2283. CAsyncOp *pAsyncOp;
  2284. CAsyncOp *pParent;
  2285. CAsyncOp *pHandleParent;
  2286. CConnection *pConnection;
  2287. DPFX(DPFPREP, 2,"Parameters: dpnid [0x%lx], prgBufferDesc [0x%p], dwTimeOut [%ld], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
  2288. dpnid,prgBufferDesc,dwTimeOut,pvAsyncContext,phAsyncHandle,dwFlags);
  2289. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  2290. DNASSERT(pdnObject != NULL);
  2291. #ifndef DPNBUILD_NOPARAMVAL
  2292. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  2293. {
  2294. if( FAILED( hResultCode = DN_ValidateSendParams( pv , prgBufferDesc, cBufferDesc, dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags ) ) )
  2295. {
  2296. DPFX(DPFPREP, 0, "Error validating common send params hr=[0x%lx]", hResultCode );
  2297. DPF_RETURN( hResultCode );
  2298. }
  2299. }
  2300. #endif // !DPNBUILD_NOPARAMVAL
  2301. // Check to ensure message handler registered
  2302. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  2303. {
  2304. DPFERR( "Object is not initialized" );
  2305. DPF_RETURN(DPNERR_UNINITIALIZED);
  2306. }
  2307. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  2308. {
  2309. DPFERR( "Object has not yet completed connecting / hosting" );
  2310. DPF_RETURN(DPNERR_CONNECTING);
  2311. }
  2312. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  2313. {
  2314. DPFERR("Object is not connected or hosting" );
  2315. DPF_RETURN(DPNERR_NOCONNECTION);
  2316. }
  2317. pRefCountBuffer = NULL;
  2318. pSyncEvent = NULL;
  2319. pNTEntry = NULL;
  2320. pLocalPlayer = NULL;
  2321. pAsyncOp = NULL;
  2322. pParent = NULL;
  2323. pHandleParent = NULL;
  2324. pConnection = NULL;
  2325. handle = 0;
  2326. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT)
  2327. {
  2328. if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pNTEntry )) != DPN_OK)
  2329. {
  2330. DPFERR("Could not find Host player");
  2331. DisplayDNError(0,hResultCode);
  2332. hResultCode = DPNERR_INVALIDPLAYER;
  2333. goto Failure;
  2334. }
  2335. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
  2336. {
  2337. DPFERR("Could not get Connection reference");
  2338. DisplayDNError(0,hResultCode);
  2339. hResultCode = DPNERR_CONNECTIONLOST; // re-map this
  2340. goto Failure;
  2341. }
  2342. pNTEntry->Release();
  2343. pNTEntry = NULL;
  2344. }
  2345. #ifndef DPNBUILD_NOMULTICAST
  2346. else if (pdnObject->dwFlags & DN_OBJECT_FLAG_MULTICAST)
  2347. {
  2348. if (pdnObject->pMulticastSend == NULL)
  2349. {
  2350. DPFERR("Could not get multicast send connection");
  2351. hResultCode = DPNERR_INVALIDGROUP;
  2352. goto Failure;
  2353. }
  2354. pdnObject->pMulticastSend->AddRef();
  2355. pConnection = pdnObject->pMulticastSend;
  2356. }
  2357. #endif // ! DPNBUILD_NOMULTICAST
  2358. else
  2359. {
  2360. if (dpnid == DPNID_ALL_PLAYERS_GROUP)
  2361. {
  2362. if ((hResultCode = pdnObject->NameTable.GetAllPlayersGroupRef( &pNTEntry )) != DPN_OK)
  2363. {
  2364. DPFERR("Unable to get all players group");
  2365. DisplayDNError(0,hResultCode);
  2366. hResultCode = DPNERR_INVALIDGROUP;
  2367. goto Failure;
  2368. }
  2369. }
  2370. else
  2371. {
  2372. if (dwFlags & DPNSEND_NOLOOPBACK)
  2373. {
  2374. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  2375. {
  2376. DPFERR("Could not get local player reference");
  2377. DisplayDNError(0,hResultCode);
  2378. hResultCode = DPNERR_GENERIC;
  2379. goto Failure;
  2380. }
  2381. if (dpnid == pLocalPlayer->GetDPNID())
  2382. {
  2383. hResultCode = DPNERR_INVALIDPARAM;
  2384. goto Failure;
  2385. }
  2386. pLocalPlayer->Release();
  2387. pLocalPlayer = NULL;
  2388. }
  2389. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  2390. {
  2391. DPFERR("Unable to find target player or group");
  2392. DisplayDNError(0,hResultCode);
  2393. //
  2394. // Try deleted list
  2395. //
  2396. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  2397. {
  2398. DPFERR("Could not find target in deleted list either");
  2399. hResultCode = DPNERR_INVALIDPLAYER;
  2400. goto Failure;
  2401. }
  2402. pNTEntry->Release();
  2403. pNTEntry = NULL;
  2404. //
  2405. // Target was found, but is not reachable
  2406. //
  2407. hResultCode = DPNERR_CONNECTIONLOST;
  2408. goto Failure;
  2409. }
  2410. if (! pNTEntry->IsGroup())
  2411. {
  2412. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
  2413. {
  2414. DPFERR("Could not get Connection reference");
  2415. DisplayDNError(0,hResultCode);
  2416. hResultCode = DPNERR_CONNECTIONLOST; // re-map this
  2417. goto Failure;
  2418. }
  2419. pNTEntry->Release();
  2420. pNTEntry = NULL;
  2421. }
  2422. }
  2423. }
  2424. //
  2425. // Create copy of data in scatter-gather buffers
  2426. //
  2427. if (!(dwFlags & (DPNSEND_NOCOPY | DPNSEND_COMPLETEONPROCESS)))
  2428. {
  2429. DWORD dw;
  2430. DWORD dwSize;
  2431. dwSize = 0;
  2432. for ( dw = 0 ; dw < cBufferDesc ; dw++ )
  2433. {
  2434. dwSize += prgBufferDesc[dw].dwBufferSize;
  2435. }
  2436. if ((hResultCode = RefCountBufferNew(pdnObject,dwSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  2437. {
  2438. DPFERR("Could not allocate buffer");
  2439. DisplayDNError(0,hResultCode);
  2440. goto Failure;
  2441. }
  2442. pActualBufferDesc = pRefCountBuffer->BufferDescAddress();
  2443. dwActualBufferDesc = 1;
  2444. dwSize = 0;
  2445. for ( dw = 0 ; dw < cBufferDesc ; dw++ )
  2446. {
  2447. memcpy(pActualBufferDesc->pBufferData + dwSize,prgBufferDesc[dw].pBufferData,prgBufferDesc[dw].dwBufferSize);
  2448. dwSize += prgBufferDesc[dw].dwBufferSize;
  2449. }
  2450. }
  2451. else
  2452. {
  2453. pRefCountBuffer = NULL;
  2454. pActualBufferDesc = prgBufferDesc;
  2455. dwActualBufferDesc = cBufferDesc;
  2456. }
  2457. dwSendFlags = 0;
  2458. if (dwFlags & DPNSEND_GUARANTEED)
  2459. {
  2460. dwSendFlags |= DN_SENDFLAGS_RELIABLE;
  2461. }
  2462. if (dwFlags & DPNSEND_NONSEQUENTIAL)
  2463. {
  2464. dwSendFlags |= DN_SENDFLAGS_NON_SEQUENTIAL;
  2465. }
  2466. if (dwFlags & DPNSEND_PRIORITY_HIGH)
  2467. {
  2468. dwSendFlags |= DN_SENDFLAGS_HIGH_PRIORITY;
  2469. }
  2470. if (dwFlags & DPNSEND_PRIORITY_LOW)
  2471. {
  2472. dwSendFlags |= DN_SENDFLAGS_LOW_PRIORITY;
  2473. }
  2474. #ifdef DIRECTPLAYDIRECTX9
  2475. if (dwFlags & DPNSEND_COALESCE)
  2476. {
  2477. dwSendFlags |= DN_SENDFLAGS_COALESCE;
  2478. }
  2479. #endif // DIRECTPLAYDIRECTX9
  2480. if (dwFlags & DPNSEND_SYNC)
  2481. {
  2482. //
  2483. // Create SyncEvent for SYNC operation
  2484. //
  2485. if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
  2486. {
  2487. DPFERR("Could not create sync event for group sends");
  2488. DisplayDNError(0,hResultCode);
  2489. goto Failure;
  2490. }
  2491. }
  2492. else
  2493. {
  2494. //
  2495. // Create Handle for ASYNC operation
  2496. //
  2497. if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK)
  2498. {
  2499. DPFERR("Could not create AsyncOp");
  2500. DisplayDNError(0,hResultCode);
  2501. goto Failure;
  2502. }
  2503. pHandleParent->SetContext( pvAsyncContext );
  2504. pHandleParent->SetStartTime( GETTIMESTAMP() );
  2505. handle = pHandleParent->GetHandle();
  2506. }
  2507. //
  2508. // pNTEntry will be NULL if this is not a group send
  2509. // pConnection will not be NULL if this is not a group send
  2510. //
  2511. if (pNTEntry != NULL)
  2512. {
  2513. BOOL fRequest;
  2514. BOOL fNoLoopBack;
  2515. DNASSERT(pConnection == NULL);
  2516. //
  2517. // Perform group sends and get parent AsyncOp
  2518. //
  2519. if (dwFlags & DPNSEND_COMPLETEONPROCESS)
  2520. {
  2521. fRequest = TRUE;
  2522. }
  2523. else
  2524. {
  2525. fRequest = FALSE;
  2526. }
  2527. if (dwFlags & DPNSEND_NOLOOPBACK)
  2528. {
  2529. fNoLoopBack = TRUE;
  2530. }
  2531. else
  2532. {
  2533. fNoLoopBack = FALSE;
  2534. }
  2535. hResultCode = DNSendGroupMessage( pdnObject,
  2536. pNTEntry,
  2537. DN_MSG_USER_SEND,
  2538. pActualBufferDesc,
  2539. dwActualBufferDesc,
  2540. pRefCountBuffer,
  2541. dwTimeOut,
  2542. dwSendFlags,
  2543. fNoLoopBack,
  2544. fRequest,
  2545. pHandleParent,
  2546. &pParent);
  2547. if (hResultCode != DPN_OK)
  2548. {
  2549. DPFERR("SEND failed");
  2550. DisplayDNError(0,hResultCode);
  2551. goto Failure;
  2552. }
  2553. //
  2554. // Synchronous ?
  2555. //
  2556. if (dwFlags & DPNSEND_SYNC)
  2557. {
  2558. pParent->SetSyncEvent( pSyncEvent );
  2559. pParent->SetResultPointer( &hrSend );
  2560. hrSend = DPNERR_GENERIC;
  2561. }
  2562. else
  2563. {
  2564. //
  2565. // Set async completion (if required). We will only need this if the SEND succeeded.
  2566. //
  2567. if (!(dwFlags & DPNSEND_NOCOMPLETE))
  2568. {
  2569. pHandleParent->SetCompletion( DNCompleteSendHandle );
  2570. }
  2571. pHandleParent->Release();
  2572. pHandleParent = NULL;
  2573. }
  2574. pParent->Release();
  2575. pParent = NULL;
  2576. pNTEntry->Release();
  2577. pNTEntry = NULL;
  2578. }
  2579. else
  2580. {
  2581. DNASSERT(pConnection != NULL);
  2582. if (dwFlags & DPNSEND_COMPLETEONPROCESS)
  2583. {
  2584. hResultCode = DNPerformRequest( pdnObject,
  2585. DN_MSG_INTERNAL_REQ_PROCESS_COMPLETION,
  2586. pActualBufferDesc,
  2587. pConnection,
  2588. pHandleParent,
  2589. &pAsyncOp);
  2590. }
  2591. else
  2592. {
  2593. hResultCode = DNSendMessage(pdnObject,
  2594. pConnection,
  2595. DN_MSG_USER_SEND,
  2596. dpnid,
  2597. pActualBufferDesc,
  2598. dwActualBufferDesc,
  2599. pRefCountBuffer,
  2600. dwTimeOut,
  2601. dwSendFlags,
  2602. pHandleParent,
  2603. &pAsyncOp);
  2604. }
  2605. pConnection->Release();
  2606. pConnection = NULL;
  2607. if (hResultCode == DPN_OK)
  2608. {
  2609. //
  2610. // If the caller wants asynchronous, we want to guarantee that we'll always
  2611. // return DPNSUCCESS_PENDING, but since the send is already complete,
  2612. // manually generate the completion now.
  2613. // If the caller wanted synchronous, trigger the event so we drop out of
  2614. // the wait below.
  2615. //
  2616. if (dwFlags & DPNSEND_SYNC)
  2617. {
  2618. pSyncEvent->Set();
  2619. hrSend = DPN_OK;
  2620. }
  2621. else
  2622. {
  2623. //
  2624. // Immediate completion should only happen for non-guaranteed sends
  2625. // where we wouldn't be told of the RTT and retry count anyway.
  2626. //
  2627. DNASSERT(! (dwFlags & DPNSEND_GUARANTEED));
  2628. DNUserSendComplete( pdnObject,
  2629. handle,
  2630. pvAsyncContext,
  2631. pHandleParent->GetStartTime(),
  2632. DPN_OK,
  2633. -1,
  2634. 0);
  2635. pHandleParent->Release();
  2636. pHandleParent = NULL;
  2637. }
  2638. }
  2639. else
  2640. {
  2641. if (hResultCode != DPNERR_PENDING)
  2642. {
  2643. DPFERR("SEND failed");
  2644. DisplayDNError(0,hResultCode);
  2645. if (hResultCode == DPNERR_INVALIDENDPOINT)
  2646. {
  2647. hResultCode = DPNERR_CONNECTIONLOST;
  2648. }
  2649. goto Failure;
  2650. }
  2651. //
  2652. // Synchronous ?
  2653. //
  2654. if (dwFlags & DPNSEND_SYNC)
  2655. {
  2656. pAsyncOp->SetSyncEvent( pSyncEvent );
  2657. pAsyncOp->SetResultPointer( &hrSend );
  2658. hrSend = DPNERR_GENERIC;
  2659. #pragma TODO( minara, "We can be smarter about passing back errors - at least better than this !" )
  2660. }
  2661. else
  2662. {
  2663. //
  2664. // Set async completion (if required). We will only need this if the SEND succeeded.
  2665. //
  2666. if (!(dwFlags & DPNSEND_NOCOMPLETE))
  2667. {
  2668. pHandleParent->SetCompletion( DNCompleteSendHandle );
  2669. }
  2670. pHandleParent->Release();
  2671. pHandleParent = NULL;
  2672. }
  2673. pAsyncOp->Release();
  2674. pAsyncOp = NULL;
  2675. }
  2676. }
  2677. if (pRefCountBuffer)
  2678. {
  2679. pRefCountBuffer->Release();
  2680. pRefCountBuffer = NULL;
  2681. }
  2682. if (dwFlags & DPNSEND_SYNC)
  2683. {
  2684. pSyncEvent->WaitForEvent();
  2685. pSyncEvent->ReturnSelfToPool();
  2686. pSyncEvent = NULL;
  2687. hResultCode = hrSend;
  2688. }
  2689. else
  2690. {
  2691. if (phAsyncHandle != NULL)
  2692. {
  2693. *phAsyncHandle = handle;
  2694. }
  2695. hResultCode = DPNERR_PENDING;
  2696. }
  2697. Exit:
  2698. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  2699. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  2700. return(hResultCode);
  2701. Failure:
  2702. if (pHandleParent)
  2703. {
  2704. pHandleParent->Release();
  2705. pHandleParent = NULL;
  2706. }
  2707. if (pAsyncOp)
  2708. {
  2709. pAsyncOp->Release();
  2710. pAsyncOp = NULL;
  2711. }
  2712. if (pParent)
  2713. {
  2714. pParent->Release();
  2715. pParent = NULL;
  2716. }
  2717. if (handle != 0)
  2718. {
  2719. if (SUCCEEDED(pdnObject->HandleTable.Destroy( handle, (PVOID*)&pAsyncOp )))
  2720. {
  2721. // Release the HandleTable reference
  2722. pAsyncOp->Release();
  2723. pAsyncOp = NULL;
  2724. }
  2725. handle = 0;
  2726. }
  2727. if (pSyncEvent)
  2728. {
  2729. pSyncEvent->ReturnSelfToPool();
  2730. pSyncEvent = NULL;
  2731. }
  2732. if (pRefCountBuffer)
  2733. {
  2734. pRefCountBuffer->Release();
  2735. pRefCountBuffer = NULL;
  2736. }
  2737. if (pLocalPlayer)
  2738. {
  2739. pLocalPlayer->Release();
  2740. pLocalPlayer = NULL;
  2741. }
  2742. if (pNTEntry)
  2743. {
  2744. pNTEntry->Release();
  2745. pNTEntry = NULL;
  2746. }
  2747. if (pConnection)
  2748. {
  2749. pConnection->Release();
  2750. pConnection = NULL;
  2751. }
  2752. goto Exit;
  2753. }
  2754. // DN_Host
  2755. #undef DPF_MODNAME
  2756. #define DPF_MODNAME "DN_Host"
  2757. STDMETHODIMP DN_Host( PVOID pInterface,
  2758. const DPN_APPLICATION_DESC *const pdnAppDesc,
  2759. IDirectPlay8Address **const prgpDeviceInfo,
  2760. const DWORD cDeviceInfo,
  2761. const DPN_SECURITY_DESC *const pdnSecurity,
  2762. const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
  2763. void *const pvPlayerContext,
  2764. const DWORD dwFlags)
  2765. {
  2766. CNameTableEntry *pHostPlayer;
  2767. CNameTableEntry *pAllPlayersGroup;
  2768. DWORD dwCurrentDevice;
  2769. HRESULT hResultCode;
  2770. DIRECTNETOBJECT *pdnObject;
  2771. IDirectPlay8Address *rgIDevice[MAX_HOST_ADDRESSES];
  2772. DWORD dwNumDeviceAddresses;
  2773. DWORD dwListensRunning;
  2774. CConnection *pConnection;
  2775. CAsyncOp *pListenParent;
  2776. DWORD dwEnumFrameSize;
  2777. DWORD dwListenFlags;
  2778. DWORD dwUpdateFlags;
  2779. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnAppDesc [0x%p], prgpDeviceInfo [0x%p], cDeviceInfo [%ld], pdnSecurity [0x%p], pdnCredentials [0x%p], dwFlags [0x%lx]",
  2780. pInterface,pdnAppDesc,prgpDeviceInfo,cDeviceInfo,pdnSecurity,pdnCredentials,dwFlags);
  2781. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  2782. DNASSERT(pdnObject != NULL);
  2783. #ifndef DPNBUILD_NOPARAMVAL
  2784. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  2785. {
  2786. if( FAILED( hResultCode = DN_ValidateHost( pInterface, pdnAppDesc, prgpDeviceInfo, cDeviceInfo,
  2787. pdnSecurity, pdnCredentials, pvPlayerContext,
  2788. dwFlags ) ) )
  2789. {
  2790. DPFERR( "Error validating host params" );
  2791. DPF_RETURN( hResultCode );
  2792. }
  2793. }
  2794. #endif // !DPNBUILD_NOPARAMVAL
  2795. // Check to ensure message handler registered
  2796. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  2797. {
  2798. DPFERR( "Object is not initialized" );
  2799. DPF_RETURN(DPNERR_UNINITIALIZED);
  2800. }
  2801. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  2802. {
  2803. DPFERR("Object is connecting / starting to host" );
  2804. DPF_RETURN(DPNERR_CONNECTING);
  2805. }
  2806. // Check to ensure not already connected
  2807. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
  2808. {
  2809. if( DN_CHECK_LOCALHOST( pdnObject ) )
  2810. {
  2811. DPFERR("Object is already hosting" );
  2812. DPF_RETURN(DPNERR_HOSTING);
  2813. }
  2814. else
  2815. {
  2816. DPFERR("Object is already connected" );
  2817. DPF_RETURN(DPNERR_ALREADYCONNECTED);
  2818. }
  2819. }
  2820. #ifndef DPNBUILD_NOPARAMVAL
  2821. if((pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) &&
  2822. (pdnAppDesc->dwFlags & DPNSESSION_CLIENT_SERVER) )
  2823. {
  2824. DPFERR( "You cannot specify the clientserver flag in peer mode" );
  2825. DPF_RETURN(DPNERR_INVALIDPARAM);
  2826. }
  2827. #ifndef DPNBUILD_NOSERVER
  2828. if((pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) &&
  2829. !(pdnAppDesc->dwFlags & DPNSESSION_CLIENT_SERVER) )
  2830. {
  2831. DPFERR( "You MUST specify the client/server flag for client/server mode" );
  2832. DPF_RETURN(DPNERR_INVALIDPARAM);
  2833. }
  2834. #endif // !DPNBUILD_NOSERVER
  2835. #endif // !DPNBUILD_NOPARAMVAL
  2836. #ifdef DIRECTPLAYDIRECTX9
  2837. //ensure that both types of signing aren't specified
  2838. if ((pdnAppDesc->dwFlags & DPNSESSION_FAST_SIGNED) && (pdnAppDesc->dwFlags & DPNSESSION_FULL_SIGNED))
  2839. {
  2840. DPFERR( "You cannot specify both fast and full signing" );
  2841. DPF_RETURN(DPNERR_INVALIDPARAM);
  2842. }
  2843. #endif // DIRECTPLAYDIRECTX9
  2844. dwNumDeviceAddresses = 0;
  2845. pListenParent = NULL;
  2846. pConnection = NULL;
  2847. pHostPlayer = NULL;
  2848. pAllPlayersGroup = NULL;
  2849. //
  2850. // Flag as CONNECTING to prevent other operations here
  2851. //
  2852. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  2853. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_CONNECTED))
  2854. {
  2855. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2856. hResultCode = DPNERR_ALREADYCONNECTED;
  2857. goto Failure;
  2858. }
  2859. pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTING;
  2860. // Adding local host flag
  2861. pdnObject->dwFlags |= DN_OBJECT_FLAG_LOCALHOST;
  2862. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  2863. //
  2864. // Copy application description to DirectNet object
  2865. //
  2866. pdnObject->ApplicationDesc.Lock();
  2867. hResultCode = pdnObject->ApplicationDesc.Update(pdnAppDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|
  2868. DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA|DN_APPDESCINFO_FLAG_GUIDS);
  2869. pdnObject->ApplicationDesc.Unlock();
  2870. if (hResultCode != DPN_OK)
  2871. {
  2872. DPFERR("Could not update application description");
  2873. DisplayDNError(0,hResultCode);
  2874. goto Failure;
  2875. }
  2876. //
  2877. // Create Instance GUID
  2878. //
  2879. if ((hResultCode = pdnObject->ApplicationDesc.CreateNewInstanceGuid()) != DPN_OK)
  2880. {
  2881. DPFERR("Could not create instance GUID - ignore and continue");
  2882. DisplayDNError(0,hResultCode);
  2883. }
  2884. //
  2885. // Set NameTable DPNID mask
  2886. //
  2887. DPFX(DPFPREP, 5,"DPNID Mask [0x%lx]",pdnObject->ApplicationDesc.GetDPNIDMask());
  2888. pdnObject->NameTable.SetDPNIDMask( pdnObject->ApplicationDesc.GetDPNIDMask() );
  2889. //
  2890. // Create group "ALL PLAYERS"
  2891. //
  2892. if ((hResultCode = NameTableEntryNew(pdnObject,&pAllPlayersGroup)) != DPN_OK)
  2893. {
  2894. DPFERR("Could not create NameTableEntry");
  2895. DisplayDNError(0,hResultCode);
  2896. DNASSERT(FALSE);
  2897. goto Failure;
  2898. }
  2899. pAllPlayersGroup->MakeGroup();
  2900. // This function takes the lock internally
  2901. pdnObject->NameTable.MakeAllPlayersGroup(pAllPlayersGroup);
  2902. //
  2903. // Create local player
  2904. //
  2905. if ((hResultCode = NameTableEntryNew(pdnObject,&pHostPlayer)) != DPN_OK)
  2906. {
  2907. DPFERR("Could not create NameTableEntry");
  2908. DisplayDNError(0,hResultCode);
  2909. DNASSERT(FALSE);
  2910. goto Failure;
  2911. }
  2912. // This function takes the lock internally
  2913. pHostPlayer->UpdateEntryInfo( pdnObject->NameTable.GetDefaultPlayer()->GetName(),
  2914. pdnObject->NameTable.GetDefaultPlayer()->GetNameSize(),
  2915. pdnObject->NameTable.GetDefaultPlayer()->GetData(),
  2916. pdnObject->NameTable.GetDefaultPlayer()->GetDataSize(),
  2917. DPNINFO_NAME|DPNINFO_DATA,
  2918. FALSE);
  2919. pHostPlayer->SetDNETVersion( DN_VERSION_CURRENT );
  2920. #ifndef DPNBUILD_NOSERVER
  2921. if (pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER)
  2922. {
  2923. pHostPlayer->MakeServer();
  2924. }
  2925. else
  2926. #endif // !DPNBUILD_NOSERVER
  2927. {
  2928. DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_PEER);
  2929. pHostPlayer->MakePeer();
  2930. }
  2931. pHostPlayer->SetContext(pvPlayerContext);
  2932. pHostPlayer->StartConnecting();
  2933. if ((hResultCode = pdnObject->NameTable.AddEntry(pHostPlayer)) != DPN_OK)
  2934. {
  2935. DPFERR("Could not add NameTableEntry to NameTable");
  2936. DisplayDNError(0,hResultCode);
  2937. DNASSERT(FALSE);
  2938. goto Failure;
  2939. }
  2940. // Create Host's connection (NULL end point)
  2941. if ((hResultCode = ConnectionNew(pdnObject,&pConnection)) != DPN_OK)
  2942. {
  2943. DPFERR("Could not create new connection");
  2944. DisplayDNError(0,hResultCode);
  2945. DNASSERT(FALSE);
  2946. goto Failure;
  2947. }
  2948. pConnection->SetStatus( CONNECTED );
  2949. pConnection->MakeLocal();
  2950. pConnection->SetEndPt(NULL);
  2951. pConnection->SetDPNID(pHostPlayer->GetDPNID());
  2952. pdnObject->NameTable.MakeLocalPlayer(pHostPlayer);
  2953. pdnObject->NameTable.MakeHostPlayer(pHostPlayer);
  2954. //
  2955. // Make ALL_PLAYERS group available (does not indicate anything to user).
  2956. //
  2957. pAllPlayersGroup->Lock();
  2958. pAllPlayersGroup->MakeAvailable();
  2959. pAllPlayersGroup->Unlock();
  2960. pAllPlayersGroup->Release();
  2961. pAllPlayersGroup = NULL;
  2962. //
  2963. // Don't notify user of CREATE_PLAYER yet in case starting listens fails.
  2964. // This prevents them from having to handle CREATE_PLAYERs even in
  2965. // the failure case.
  2966. //
  2967. //
  2968. // Start listens
  2969. //
  2970. #if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_ONLYONEADAPTER)))
  2971. if (cDeviceInfo == 0)
  2972. {
  2973. //
  2974. // Create a placeholder device address
  2975. //
  2976. #ifdef DPNBUILD_LIBINTERFACE
  2977. hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
  2978. reinterpret_cast<void**>(&rgIDevice[0]));
  2979. #else // ! DPNBUILD_LIBINTERFACE
  2980. hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
  2981. NULL,
  2982. CLSCTX_INPROC_SERVER,
  2983. IID_IDirectPlay8Address,
  2984. reinterpret_cast<void**>(&rgIDevice[0]),
  2985. FALSE);
  2986. #endif // ! DPNBUILD_LIBINTERFACE
  2987. if (hResultCode != S_OK)
  2988. {
  2989. DPFERR("Could not create device address");
  2990. DisplayDNError(0,hResultCode);
  2991. DNASSERT(FALSE);
  2992. goto Failure;
  2993. }
  2994. dwNumDeviceAddresses = 1;
  2995. }
  2996. else
  2997. #endif // DPNBUILD_ONLYONESP and DPNBUILD_ONLYONEADAPTER
  2998. {
  2999. #ifdef DBG
  3000. for (dwCurrentDevice = 0 ; dwCurrentDevice < cDeviceInfo ; dwCurrentDevice++)
  3001. {
  3002. DPFX(DPFPREP, 5,"Original Device: prgpDeviceInfo[%ld] [0x%p]",dwCurrentDevice,prgpDeviceInfo[dwCurrentDevice]);
  3003. }
  3004. #endif // DBG
  3005. // Duplicate address interfaces
  3006. for (dwCurrentDevice = 0 ; dwCurrentDevice < cDeviceInfo ; dwCurrentDevice++)
  3007. {
  3008. if ((hResultCode = IDirectPlay8Address_Duplicate(prgpDeviceInfo[dwCurrentDevice],&rgIDevice[dwNumDeviceAddresses])) != DPN_OK)
  3009. {
  3010. DPFERR("Could not duplicate Host address info - skipping it");
  3011. continue;
  3012. }
  3013. DPFX(DPFPREP, 5,"Duplicate Device: rgIDevice[%ld] [0x%p]",dwNumDeviceAddresses,rgIDevice[dwNumDeviceAddresses]);
  3014. dwNumDeviceAddresses++;
  3015. }
  3016. }
  3017. // Parent Async Op
  3018. if ((hResultCode = AsyncOpNew(pdnObject,&pListenParent)) != DPN_OK)
  3019. {
  3020. DPFERR("Could not create AsyncOp");
  3021. DisplayDNError(0,hResultCode);
  3022. DNASSERT(FALSE);
  3023. goto Failure;
  3024. }
  3025. pListenParent->SetOpType( ASYNC_OP_LISTEN );
  3026. pListenParent->MakeParent();
  3027. pListenParent->SetCompletion( DNCompleteListen );
  3028. dwListenFlags = 0;
  3029. #ifndef DPNBUILD_NOSPUI
  3030. // Save query for addressing flag (if necessary)
  3031. if (dwFlags & DPNHOST_OKTOQUERYFORADDRESSING)
  3032. {
  3033. dwListenFlags |= DN_LISTENFLAGS_OKTOQUERYFORADDRESSING;
  3034. }
  3035. #endif // ! DPNBUILD_NOSPUI
  3036. if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0)
  3037. {
  3038. dwListenFlags |= DN_LISTENFLAGS_SESSIONDATA;
  3039. }
  3040. #ifdef DIRECTPLAYDIRECTX9
  3041. // Disallow enums if required
  3042. if (pdnAppDesc->dwFlags & DPNSESSION_NOENUMS)
  3043. {
  3044. dwListenFlags |= DN_LISTENFLAGS_DISALLOWENUMS;
  3045. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  3046. pdnObject->dwFlags |= DN_OBJECT_FLAG_DISALLOW_ENUMS;
  3047. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  3048. }
  3049. // turning signing on if required. N.B. We've already ensured that only one of these options is selected
  3050. if (pdnAppDesc->dwFlags & DPNSESSION_FAST_SIGNED)
  3051. {
  3052. dwListenFlags|=DN_LISTENFLAGS_FASTSIGNED;
  3053. }
  3054. else if (pdnAppDesc->dwFlags & DPNSESSION_FULL_SIGNED)
  3055. {
  3056. dwListenFlags|=DN_LISTENFLAGS_FULLSIGNED;
  3057. }
  3058. #endif // DIRECTPLAYDIRECTX9
  3059. pListenParent->SetOpFlags(dwListenFlags);
  3060. // Children op's
  3061. dwListensRunning = 0;
  3062. for (dwCurrentDevice = 0 ; dwCurrentDevice < dwNumDeviceAddresses ; dwCurrentDevice++)
  3063. {
  3064. if (rgIDevice[dwCurrentDevice] != NULL)
  3065. {
  3066. hResultCode = DNPerformSPListen(pdnObject,
  3067. rgIDevice[dwCurrentDevice],
  3068. pListenParent,
  3069. NULL);
  3070. if (hResultCode == DPN_OK)
  3071. {
  3072. dwListensRunning++;
  3073. }
  3074. }
  3075. }
  3076. // Make sure at least 1 listen started
  3077. if (dwListensRunning == 0)
  3078. {
  3079. DPFERR("Could not start any LISTENs");
  3080. hResultCode = DPNERR_INVALIDDEVICEADDRESS;
  3081. goto Failure;
  3082. }
  3083. // Store parent LISTEN on DirectNet object
  3084. pListenParent->AddRef();
  3085. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  3086. pdnObject->pListenParent = pListenParent;
  3087. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  3088. pListenParent->Release();
  3089. pListenParent = NULL;
  3090. //
  3091. // Use cached max enum frame size
  3092. //
  3093. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  3094. dwEnumFrameSize = pdnObject->dwMaxFrameSize;
  3095. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  3096. DNASSERT( dwEnumFrameSize >= (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)) );
  3097. if (dwEnumFrameSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO) + pdnAppDesc->dwApplicationReservedDataSize))
  3098. {
  3099. DPFERR("Not enough room for the application reserved data");
  3100. hResultCode = DPNERR_DATATOOLARGE;
  3101. goto Failure;
  3102. }
  3103. //
  3104. // Register with DPNSVR
  3105. //
  3106. dwUpdateFlags = 0;
  3107. #ifndef DPNBUILD_SINGLEPROCESS
  3108. if(pdnObject->ApplicationDesc.UseDPNSVR())
  3109. {
  3110. dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DPNSVR;
  3111. }
  3112. #endif // ! DPNBUILD_SINGLEPROCESS
  3113. if (pdnObject->ApplicationDesc.DisallowEnums())
  3114. {
  3115. dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS;
  3116. }
  3117. if (dwUpdateFlags)
  3118. {
  3119. if ((hResultCode = DNUpdateListens(pdnObject,dwUpdateFlags)) != DPN_OK)
  3120. {
  3121. DPFERR("Could not update listens or register with DPNSVR");
  3122. DisplayDNError(0,hResultCode);
  3123. goto Failure;
  3124. }
  3125. }
  3126. //
  3127. // Update DirectNet object to be connected
  3128. //
  3129. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  3130. DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING);
  3131. pdnObject->dwFlags &= ~DN_OBJECT_FLAG_CONNECTING;
  3132. pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED;
  3133. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  3134. #ifndef DPNBUILD_NOLOBBY
  3135. //
  3136. // Update Lobby status
  3137. //
  3138. DNUpdateLobbyStatus(pdnObject,DPLSESSION_CONNECTED);
  3139. #endif // ! DPNBUILD_NOLOBBY
  3140. //
  3141. // Now that Listens have been successfully started, indicate the local CREATE_PLAYER.
  3142. //
  3143. //
  3144. // One player in game (Local/Host player)
  3145. //
  3146. pdnObject->ApplicationDesc.IncPlayerCount(TRUE);
  3147. //
  3148. // Populate local player's connection
  3149. //
  3150. pConnection->SetDPNID(pHostPlayer->GetDPNID());
  3151. pdnObject->NameTable.PopulateConnection(pConnection);
  3152. pConnection->Release();
  3153. pConnection = NULL;
  3154. #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
  3155. //
  3156. // Unload SP's
  3157. //
  3158. DN_SPReleaseAll(pdnObject);
  3159. #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
  3160. pHostPlayer->Release();
  3161. pHostPlayer = NULL;
  3162. hResultCode = DPN_OK;
  3163. Exit:
  3164. //
  3165. // Clean up copies of device address
  3166. //
  3167. for (dwCurrentDevice = 0 ; dwCurrentDevice < dwNumDeviceAddresses ; dwCurrentDevice++)
  3168. {
  3169. IDirectPlay8Address_Release(rgIDevice[dwCurrentDevice]);
  3170. rgIDevice[dwCurrentDevice] = NULL;
  3171. }
  3172. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  3173. return(hResultCode);
  3174. Failure:
  3175. if (pConnection)
  3176. {
  3177. pConnection->Release();
  3178. pConnection = NULL;
  3179. }
  3180. if (pListenParent)
  3181. {
  3182. pListenParent->Release();
  3183. pListenParent = NULL;
  3184. }
  3185. if (pHostPlayer)
  3186. {
  3187. pHostPlayer->Release();
  3188. pHostPlayer = NULL;
  3189. }
  3190. if (pAllPlayersGroup)
  3191. {
  3192. pAllPlayersGroup->Release();
  3193. pAllPlayersGroup = NULL;
  3194. }
  3195. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  3196. pListenParent = pdnObject->pListenParent;
  3197. pdnObject->pListenParent = NULL;
  3198. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  3199. if (pListenParent)
  3200. {
  3201. DNCancelChildren(pdnObject,pListenParent);
  3202. pListenParent->Release();
  3203. pListenParent = NULL;
  3204. }
  3205. pdnObject->NameTable.EmptyTable(DPNERR_HOSTTERMINATEDSESSION);
  3206. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  3207. pdnObject->dwFlags &= ~(DN_OBJECT_FLAG_CONNECTING|DN_OBJECT_FLAG_CONNECTED|DN_OBJECT_FLAG_LOCALHOST);
  3208. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  3209. goto Exit;
  3210. }
  3211. #undef DPF_MODNAME
  3212. #define DPF_MODNAME "DN_CreateGroup"
  3213. STDMETHODIMP DN_CreateGroup(PVOID pInterface,
  3214. const DPN_GROUP_INFO *const pdpnGroupInfo,
  3215. void *const pvGroupContext,
  3216. void *const pvAsyncContext,
  3217. DPNHANDLE *const phAsyncHandle,
  3218. const DWORD dwFlags)
  3219. {
  3220. DIRECTNETOBJECT *pdnObject;
  3221. HRESULT hResultCode;
  3222. DPNHANDLE hAsyncOp;
  3223. PWSTR pwszName;
  3224. DWORD dwNameSize;
  3225. PVOID pvData;
  3226. DWORD dwDataSize;
  3227. CNameTableEntry *pLocalPlayer;
  3228. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdpnGroupInfo [0x%p], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
  3229. pInterface,pdpnGroupInfo,pvAsyncContext,phAsyncHandle,dwFlags);
  3230. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  3231. DNASSERT(pdnObject != NULL);
  3232. #ifndef DPNBUILD_NOPARAMVAL
  3233. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  3234. {
  3235. if( FAILED( hResultCode = DN_ValidateCreateGroup( pInterface, pdpnGroupInfo, pvGroupContext,
  3236. pvAsyncContext,phAsyncHandle, dwFlags ) ) )
  3237. {
  3238. DPFERR( "Error validating create group params" );
  3239. DPF_RETURN( hResultCode );
  3240. }
  3241. }
  3242. #endif // !DPNBUILD_NOPARAMVAL
  3243. // Check to ensure message handler registered
  3244. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  3245. {
  3246. DPFERR( "Object is not initialized" );
  3247. DPF_RETURN(DPNERR_UNINITIALIZED);
  3248. }
  3249. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  3250. {
  3251. DPFERR("Object is connecting / starting to host" );
  3252. DPF_RETURN(DPNERR_CONNECTING);
  3253. }
  3254. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  3255. {
  3256. DPFERR("You must be connected / hosting to create a group" );
  3257. DPF_RETURN(DPNERR_NOCONNECTION);
  3258. }
  3259. pLocalPlayer = NULL;
  3260. if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_NAME) && (pdpnGroupInfo->pwszName))
  3261. {
  3262. pwszName = pdpnGroupInfo->pwszName;
  3263. dwNameSize = (wcslen(pwszName) + 1) * sizeof(WCHAR);
  3264. }
  3265. else
  3266. {
  3267. pwszName = NULL;
  3268. dwNameSize = 0;
  3269. }
  3270. if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_DATA) && (pdpnGroupInfo->pvData) && (pdpnGroupInfo->dwDataSize))
  3271. {
  3272. pvData = pdpnGroupInfo->pvData;
  3273. dwDataSize = pdpnGroupInfo->dwDataSize;
  3274. }
  3275. else
  3276. {
  3277. pvData = NULL;
  3278. dwDataSize = 0;
  3279. }
  3280. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  3281. {
  3282. DPFERR("Could not get local player reference");
  3283. DisplayDNError(0,hResultCode);
  3284. goto Failure;
  3285. }
  3286. if (pLocalPlayer->IsHost())
  3287. {
  3288. DPFX(DPFPREP, 3,"Host is creating group");
  3289. hResultCode = DNHostCreateGroup(pdnObject,
  3290. pwszName,
  3291. dwNameSize,
  3292. pvData,
  3293. dwDataSize,
  3294. pdpnGroupInfo->dwInfoFlags,
  3295. pdpnGroupInfo->dwGroupFlags,
  3296. pvGroupContext,
  3297. pvAsyncContext,
  3298. pLocalPlayer->GetDPNID(),
  3299. 0,
  3300. &hAsyncOp,
  3301. dwFlags);
  3302. if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
  3303. {
  3304. DPFERR("Could not request host to create group");
  3305. }
  3306. else
  3307. {
  3308. if (!(dwFlags & DPNCREATEGROUP_SYNC))
  3309. {
  3310. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3311. *phAsyncHandle = hAsyncOp;
  3312. //
  3313. // Release Async HANDLE since this operation has already completed (!)
  3314. //
  3315. CAsyncOp* pAsyncOp;
  3316. if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
  3317. {
  3318. // Release the HandleTable reference
  3319. pAsyncOp->Release();
  3320. pAsyncOp = NULL;
  3321. }
  3322. hAsyncOp = 0;
  3323. }
  3324. }
  3325. }
  3326. else
  3327. {
  3328. DPFX(DPFPREP, 3,"Request host to create group");
  3329. hResultCode = DNRequestCreateGroup( pdnObject,
  3330. pwszName,
  3331. dwNameSize,
  3332. pvData,
  3333. dwDataSize,
  3334. pdpnGroupInfo->dwGroupFlags,
  3335. pvGroupContext,
  3336. pvAsyncContext,
  3337. &hAsyncOp,
  3338. dwFlags);
  3339. if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
  3340. {
  3341. DPFERR("Could not request host to create group");
  3342. hResultCode = DPNERR_GENERIC;
  3343. #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
  3344. }
  3345. else
  3346. {
  3347. if (!(dwFlags & DPNCREATEGROUP_SYNC))
  3348. {
  3349. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3350. *phAsyncHandle = hAsyncOp;
  3351. }
  3352. }
  3353. }
  3354. pLocalPlayer->Release();
  3355. pLocalPlayer = NULL;
  3356. Exit:
  3357. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  3358. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  3359. return(hResultCode);
  3360. Failure:
  3361. if (pLocalPlayer)
  3362. {
  3363. pLocalPlayer->Release();
  3364. pLocalPlayer = NULL;
  3365. }
  3366. goto Exit;
  3367. }
  3368. #undef DPF_MODNAME
  3369. #define DPF_MODNAME "DN_DestroyGroup"
  3370. STDMETHODIMP DN_DestroyGroup(PVOID pInterface,
  3371. const DPNID dpnidGroup,
  3372. PVOID const pvAsyncContext,
  3373. DPNHANDLE *const phAsyncHandle,
  3374. const DWORD dwFlags)
  3375. {
  3376. DIRECTNETOBJECT *pdnObject;
  3377. HRESULT hResultCode;
  3378. DPNHANDLE hAsyncOp;
  3379. CNameTableEntry *pLocalPlayer;
  3380. CNameTableEntry *pNTEntry;
  3381. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
  3382. pInterface,dpnidGroup,pvAsyncContext,phAsyncHandle,dwFlags);
  3383. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  3384. DNASSERT(pdnObject != NULL);
  3385. #ifndef DPNBUILD_NOPARAMVAL
  3386. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  3387. {
  3388. if( FAILED( hResultCode = DN_ValidateDestroyGroup( pInterface, dpnidGroup, pvAsyncContext,
  3389. phAsyncHandle, dwFlags ) ) )
  3390. {
  3391. DPFERR( "Error validating destroy group params" );
  3392. DPF_RETURN( hResultCode );
  3393. }
  3394. }
  3395. #endif // !DPNBUILD_NOPARAMVAL
  3396. // Check to ensure message handler registered
  3397. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  3398. {
  3399. DPFERR( "Object is not initialized" );
  3400. DPF_RETURN(DPNERR_UNINITIALIZED);
  3401. }
  3402. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  3403. {
  3404. DPFERR("Object is connecting / starting to host" );
  3405. DPF_RETURN(DPNERR_CONNECTING);
  3406. }
  3407. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  3408. {
  3409. DPFERR("You must be connected / hosting to destroy a group" );
  3410. DPF_RETURN(DPNERR_NOCONNECTION);
  3411. }
  3412. pLocalPlayer = NULL;
  3413. pNTEntry = NULL;
  3414. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
  3415. {
  3416. DPFERR( "Could not find specified group" );
  3417. DisplayDNError(0,hResultCode);
  3418. //
  3419. // Try deleted list
  3420. //
  3421. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
  3422. {
  3423. hResultCode = DPNERR_INVALIDGROUP;
  3424. goto Failure;
  3425. }
  3426. pNTEntry->Release();
  3427. pNTEntry = NULL;
  3428. hResultCode = DPNERR_CONNECTIONLOST;
  3429. goto Failure;
  3430. }
  3431. if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
  3432. {
  3433. hResultCode = DPNERR_INVALIDGROUP;
  3434. goto Failure;
  3435. }
  3436. pNTEntry->Release();
  3437. pNTEntry = NULL;
  3438. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  3439. {
  3440. DPFERR("Could not get local player reference");
  3441. DisplayDNError(0,hResultCode);
  3442. goto Failure;
  3443. }
  3444. if (pLocalPlayer->IsHost())
  3445. {
  3446. DPFX(DPFPREP, 3,"Host is destroying group");
  3447. hResultCode = DNHostDestroyGroup( pdnObject,
  3448. dpnidGroup,
  3449. pvAsyncContext,
  3450. pLocalPlayer->GetDPNID(),
  3451. 0,
  3452. &hAsyncOp,
  3453. dwFlags);
  3454. if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
  3455. {
  3456. DPFERR("Could not request host to destroy group");
  3457. }
  3458. else
  3459. {
  3460. if (!(dwFlags & DPNDESTROYGROUP_SYNC))
  3461. {
  3462. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3463. *phAsyncHandle = hAsyncOp;
  3464. //
  3465. // Release Async HANDLE since this operation has already completed (!)
  3466. //
  3467. CAsyncOp* pAsyncOp;
  3468. if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
  3469. {
  3470. // Release the HandleTable reference
  3471. pAsyncOp->Release();
  3472. pAsyncOp = NULL;
  3473. }
  3474. hAsyncOp = 0;
  3475. }
  3476. }
  3477. }
  3478. else
  3479. {
  3480. DPFX(DPFPREP, 3,"Request host to destroy group");
  3481. hResultCode = DNRequestDestroyGroup(pdnObject,
  3482. dpnidGroup,
  3483. pvAsyncContext,
  3484. &hAsyncOp,
  3485. dwFlags);
  3486. if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
  3487. {
  3488. DPFERR("Could not request host to destroy group");
  3489. hResultCode = DPNERR_GENERIC;
  3490. #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
  3491. }
  3492. else
  3493. {
  3494. if (!(dwFlags & DPNDESTROYGROUP_SYNC))
  3495. {
  3496. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3497. *phAsyncHandle = hAsyncOp;
  3498. }
  3499. }
  3500. }
  3501. pLocalPlayer->Release();
  3502. pLocalPlayer = NULL;
  3503. Exit:
  3504. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  3505. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  3506. return(hResultCode);
  3507. Failure:
  3508. if (pLocalPlayer)
  3509. {
  3510. pLocalPlayer->Release();
  3511. pLocalPlayer = NULL;
  3512. }
  3513. if (pNTEntry)
  3514. {
  3515. pNTEntry->Release();
  3516. pNTEntry = NULL;
  3517. }
  3518. goto Exit;
  3519. }
  3520. #undef DPF_MODNAME
  3521. #define DPF_MODNAME "DN_AddClientToGroup"
  3522. STDMETHODIMP DN_AddClientToGroup(PVOID pInterface,
  3523. const DPNID dpnidGroup,
  3524. const DPNID dpnidClient,
  3525. PVOID const pvAsyncContext,
  3526. DPNHANDLE *const phAsyncHandle,
  3527. const DWORD dwFlags)
  3528. {
  3529. DIRECTNETOBJECT *pdnObject;
  3530. HRESULT hResultCode;
  3531. DPNHANDLE hAsyncOp;
  3532. CNameTableEntry *pLocalPlayer;
  3533. CNameTableEntry *pNTEntry;
  3534. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], dpnidClient [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
  3535. pInterface,dpnidGroup,dpnidClient,pvAsyncContext,phAsyncHandle,dwFlags);
  3536. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  3537. DNASSERT(pdnObject != NULL);
  3538. #ifndef DPNBUILD_NOPARAMVAL
  3539. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  3540. {
  3541. if( FAILED( hResultCode = DN_ValidateAddClientToGroup( pInterface, dpnidGroup, dpnidClient, pvAsyncContext,
  3542. phAsyncHandle, dwFlags ) ))
  3543. {
  3544. DPFERR( "Error validating add client to group params" );
  3545. DPF_RETURN( hResultCode );
  3546. }
  3547. }
  3548. #endif // !DPNBUILD_NOPARAMVAL
  3549. // Check to ensure message handler registered
  3550. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  3551. {
  3552. DPFERR( "Object is not initialized" );
  3553. DPF_RETURN(DPNERR_UNINITIALIZED);
  3554. }
  3555. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  3556. {
  3557. DPFERR("Object is connecting / starting to host" );
  3558. DPF_RETURN(DPNERR_CONNECTING);
  3559. }
  3560. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  3561. {
  3562. DPFERR("You must be connected / hosting to add a player to a group" );
  3563. DPF_RETURN(DPNERR_NOCONNECTION);
  3564. }
  3565. pLocalPlayer = NULL;
  3566. pNTEntry = NULL;
  3567. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
  3568. {
  3569. DPFERR( "Unable to find specified group" );
  3570. hResultCode = DPNERR_INVALIDGROUP;
  3571. goto Failure;
  3572. }
  3573. if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
  3574. {
  3575. DPFERR( "Unable to specify client or all players group for group ID" );
  3576. hResultCode = DPNERR_INVALIDGROUP;
  3577. goto Failure;
  3578. }
  3579. pNTEntry->Release();
  3580. pNTEntry = NULL;
  3581. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidClient,&pNTEntry)) != DPN_OK)
  3582. {
  3583. DPFERR( "Unable to find specified player" );
  3584. hResultCode = DPNERR_INVALIDPLAYER;
  3585. goto Failure;
  3586. }
  3587. if (pNTEntry->IsGroup())
  3588. {
  3589. DPFERR( "Specified client is a group ID" );
  3590. hResultCode = DPNERR_INVALIDPLAYER;
  3591. goto Failure;
  3592. }
  3593. pNTEntry->Release();
  3594. pNTEntry = NULL;
  3595. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  3596. {
  3597. DPFERR("Could not get local player reference");
  3598. DisplayDNError(0,hResultCode);
  3599. goto Failure;
  3600. }
  3601. if (pLocalPlayer->IsHost())
  3602. {
  3603. DPFX(DPFPREP, 3,"Host is adding player to group");
  3604. hResultCode = DNHostAddPlayerToGroup( pdnObject,
  3605. dpnidGroup,
  3606. dpnidClient,
  3607. pvAsyncContext,
  3608. pLocalPlayer->GetDPNID(),
  3609. 0,
  3610. &hAsyncOp,
  3611. dwFlags);
  3612. if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
  3613. {
  3614. DPFERR("Could not request host to add player to group");
  3615. }
  3616. else
  3617. {
  3618. if (!(dwFlags & DPNADDPLAYERTOGROUP_SYNC))
  3619. {
  3620. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3621. *phAsyncHandle = hAsyncOp;
  3622. //
  3623. // Release Async HANDLE since this operation has already completed (!)
  3624. //
  3625. CAsyncOp* pAsyncOp;
  3626. if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
  3627. {
  3628. // Release the HandleTable reference
  3629. pAsyncOp->Release();
  3630. pAsyncOp = NULL;
  3631. }
  3632. hAsyncOp = 0;
  3633. }
  3634. }
  3635. }
  3636. else
  3637. {
  3638. DPFX(DPFPREP, 3,"Request host to add player to group");
  3639. hResultCode = DNRequestAddPlayerToGroup(pdnObject,
  3640. dpnidGroup,
  3641. dpnidClient,
  3642. pvAsyncContext,
  3643. &hAsyncOp,
  3644. dwFlags);
  3645. if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
  3646. {
  3647. DPFERR("Could not request host to add player to group");
  3648. hResultCode = DPNERR_GENERIC;
  3649. #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
  3650. }
  3651. else
  3652. {
  3653. if (!(dwFlags & DPNADDPLAYERTOGROUP_SYNC))
  3654. {
  3655. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3656. *phAsyncHandle = hAsyncOp;
  3657. }
  3658. }
  3659. }
  3660. pLocalPlayer->Release();
  3661. pLocalPlayer = NULL;
  3662. Exit:
  3663. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  3664. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  3665. return(hResultCode);
  3666. Failure:
  3667. if (pLocalPlayer)
  3668. {
  3669. pLocalPlayer->Release();
  3670. pLocalPlayer = NULL;
  3671. }
  3672. if (pNTEntry)
  3673. {
  3674. pNTEntry->Release();
  3675. pNTEntry = NULL;
  3676. }
  3677. goto Exit;
  3678. }
  3679. #undef DPF_MODNAME
  3680. #define DPF_MODNAME "DN_RemoveClientFromGroup"
  3681. STDMETHODIMP DN_RemoveClientFromGroup(PVOID pInterface,
  3682. const DPNID dpnidGroup,
  3683. const DPNID dpnidClient,
  3684. PVOID const pvAsyncContext,
  3685. DPNHANDLE *const phAsyncHandle,
  3686. const DWORD dwFlags)
  3687. {
  3688. DIRECTNETOBJECT *pdnObject;
  3689. HRESULT hResultCode;
  3690. DPNHANDLE hAsyncOp;
  3691. CNameTableEntry *pLocalPlayer;
  3692. CNameTableEntry *pNTEntry;
  3693. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], dpnidClient [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
  3694. pInterface,dpnidGroup,dpnidClient,pvAsyncContext,phAsyncHandle,dwFlags);
  3695. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  3696. DNASSERT(pdnObject != NULL);
  3697. #ifndef DPNBUILD_NOPARAMVAL
  3698. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  3699. {
  3700. if( FAILED( hResultCode = DN_ValidateRemoveClientFromGroup( pInterface, dpnidGroup, dpnidClient, pvAsyncContext, phAsyncHandle, dwFlags ) ))
  3701. {
  3702. DPFERR( "Error validating remove client from group params" );
  3703. DPF_RETURN( hResultCode );
  3704. }
  3705. }
  3706. #endif // !DPNBUILD_NOPARAMVAL
  3707. // Check to ensure message handler registered
  3708. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  3709. {
  3710. DPFERR( "Object is not initialized" );
  3711. DPF_RETURN(DPNERR_UNINITIALIZED);
  3712. }
  3713. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  3714. {
  3715. DPFERR("Object is connecting / starting to host" );
  3716. DPF_RETURN(DPNERR_CONNECTING);
  3717. }
  3718. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  3719. {
  3720. DPFERR("You must be connected / hosting to remove a player from a group" );
  3721. DPF_RETURN(DPNERR_NOCONNECTION);
  3722. }
  3723. pLocalPlayer = NULL;
  3724. pNTEntry = NULL;
  3725. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK)
  3726. {
  3727. DPFERR( "Could not find specified group in nametable" );
  3728. hResultCode = DPNERR_INVALIDGROUP;
  3729. goto Failure;
  3730. }
  3731. if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
  3732. {
  3733. DPFERR( "Specified ID is not a valid group!" );
  3734. hResultCode = DPNERR_INVALIDGROUP;
  3735. goto Failure;
  3736. }
  3737. pNTEntry->Release();
  3738. pNTEntry = NULL;
  3739. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidClient,&pNTEntry)) != DPN_OK)
  3740. {
  3741. DPFERR( "Specified client ID is not a valid client!" );
  3742. hResultCode = DPNERR_INVALIDPLAYER;
  3743. goto Failure;
  3744. }
  3745. if (pNTEntry->IsGroup())
  3746. {
  3747. DPFERR( "Specified client ID is a group!" );
  3748. hResultCode = DPNERR_INVALIDPLAYER;
  3749. goto Failure;
  3750. }
  3751. pNTEntry->Release();
  3752. pNTEntry = NULL;
  3753. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  3754. {
  3755. DPFERR("Could not get local player reference");
  3756. DisplayDNError(0,hResultCode);
  3757. goto Failure;
  3758. }
  3759. if (pLocalPlayer->IsHost())
  3760. {
  3761. DPFX(DPFPREP, 3,"Host is deleting player from group");
  3762. hResultCode = DNHostDeletePlayerFromGroup( pdnObject,
  3763. dpnidGroup,
  3764. dpnidClient,
  3765. pvAsyncContext,
  3766. pLocalPlayer->GetDPNID(),
  3767. 0,
  3768. &hAsyncOp,
  3769. dwFlags);
  3770. if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
  3771. {
  3772. DPFERR("Could not request host to delete player from group");
  3773. }
  3774. else
  3775. {
  3776. if (!(dwFlags & DPNREMOVEPLAYERFROMGROUP_SYNC))
  3777. {
  3778. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3779. *phAsyncHandle = hAsyncOp;
  3780. //
  3781. // Release Async HANDLE since this operation has already completed (!)
  3782. //
  3783. CAsyncOp* pAsyncOp;
  3784. if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
  3785. {
  3786. // Release the HandleTable reference
  3787. pAsyncOp->Release();
  3788. pAsyncOp = NULL;
  3789. }
  3790. hAsyncOp = 0;
  3791. }
  3792. }
  3793. }
  3794. else
  3795. {
  3796. DPFX(DPFPREP, 3,"Request host to delete player from group");
  3797. hResultCode = DNRequestDeletePlayerFromGroup(pdnObject,
  3798. dpnidGroup,
  3799. dpnidClient,
  3800. pvAsyncContext,
  3801. &hAsyncOp,
  3802. dwFlags);
  3803. if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
  3804. {
  3805. DPFERR("Could not request host to delete player from group");
  3806. hResultCode = DPNERR_GENERIC;
  3807. #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
  3808. }
  3809. else
  3810. {
  3811. if (!(dwFlags & DPNREMOVEPLAYERFROMGROUP_SYNC))
  3812. {
  3813. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3814. *phAsyncHandle = hAsyncOp;
  3815. }
  3816. }
  3817. }
  3818. pLocalPlayer->Release();
  3819. pLocalPlayer = NULL;
  3820. Exit:
  3821. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  3822. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  3823. return(hResultCode);
  3824. Failure:
  3825. if (pLocalPlayer)
  3826. {
  3827. pLocalPlayer->Release();
  3828. pLocalPlayer = NULL;
  3829. }
  3830. if (pNTEntry)
  3831. {
  3832. pNTEntry->Release();
  3833. pNTEntry = NULL;
  3834. }
  3835. goto Exit;
  3836. }
  3837. // DN_SetGroupInfo
  3838. #undef DPF_MODNAME
  3839. #define DPF_MODNAME "DN_SetGroupInfo"
  3840. STDMETHODIMP DN_SetGroupInfo( PVOID pv,
  3841. const DPNID dpnid,
  3842. DPN_GROUP_INFO *const pdpnGroupInfo,
  3843. PVOID const pvAsyncContext,
  3844. DPNHANDLE *const phAsyncHandle,
  3845. const DWORD dwFlags)
  3846. {
  3847. DIRECTNETOBJECT *pdnObject;
  3848. HRESULT hResultCode;
  3849. DPNHANDLE hAsyncOp;
  3850. PWSTR pwszName;
  3851. DWORD dwNameSize;
  3852. PVOID pvData;
  3853. DWORD dwDataSize;
  3854. CNameTableEntry *pLocalPlayer;
  3855. CNameTableEntry *pNTEntry;
  3856. DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
  3857. pv,dpnid,pdpnGroupInfo,pvAsyncContext,phAsyncHandle,dwFlags);
  3858. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  3859. DNASSERT(pdnObject != NULL);
  3860. #ifndef DPNBUILD_NOPARAMVAL
  3861. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  3862. {
  3863. if( FAILED( hResultCode = DN_ValidateSetGroupInfo( pv, dpnid, pdpnGroupInfo, pvAsyncContext, phAsyncHandle, dwFlags ) ) )
  3864. {
  3865. DPFERR( "Error validating set group info params" );
  3866. DPF_RETURN( hResultCode );
  3867. }
  3868. }
  3869. #endif // DPNBUILD_NOPARAMVAL
  3870. // Check to ensure message handler registered
  3871. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  3872. {
  3873. DPFERR( "Object is not initialized" );
  3874. DPF_RETURN(DPNERR_UNINITIALIZED);
  3875. }
  3876. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  3877. {
  3878. DPFERR("Object is connecting / starting to host" );
  3879. DPF_RETURN(DPNERR_CONNECTING);
  3880. }
  3881. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  3882. {
  3883. DPFERR("You must be connected / hosting to set group info" );
  3884. DPF_RETURN(DPNERR_NOCONNECTION);
  3885. }
  3886. pLocalPlayer = NULL;
  3887. pNTEntry = NULL;
  3888. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  3889. {
  3890. DPFERR( "Specified ID is not a group" );
  3891. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  3892. {
  3893. hResultCode = DPNERR_INVALIDGROUP;
  3894. goto Failure;
  3895. }
  3896. pNTEntry->Release();
  3897. pNTEntry = NULL;
  3898. hResultCode = DPNERR_CONNECTIONLOST;
  3899. goto Failure;
  3900. }
  3901. if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
  3902. {
  3903. DPFERR( "Specified ID is not a valid group" );
  3904. hResultCode = DPNERR_INVALIDGROUP;
  3905. goto Failure;
  3906. }
  3907. pNTEntry->Release();
  3908. pNTEntry = NULL;
  3909. if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_NAME) && (pdpnGroupInfo->pwszName))
  3910. {
  3911. pwszName = pdpnGroupInfo->pwszName;
  3912. dwNameSize = (wcslen(pwszName) + 1) * sizeof(WCHAR);
  3913. }
  3914. else
  3915. {
  3916. pwszName = NULL;
  3917. dwNameSize = 0;
  3918. }
  3919. if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_DATA) && (pdpnGroupInfo->pvData) && (pdpnGroupInfo->dwDataSize))
  3920. {
  3921. pvData = pdpnGroupInfo->pvData;
  3922. dwDataSize = pdpnGroupInfo->dwDataSize;
  3923. }
  3924. else
  3925. {
  3926. pvData = NULL;
  3927. dwDataSize = 0;
  3928. }
  3929. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  3930. {
  3931. DPFERR("Could not get local player reference");
  3932. DisplayDNError(0,hResultCode);
  3933. goto Failure;
  3934. }
  3935. if (pLocalPlayer->IsHost())
  3936. {
  3937. DPFX(DPFPREP, 3,"Host is updating group info");
  3938. hResultCode = DNHostUpdateInfo( pdnObject,
  3939. dpnid,
  3940. pwszName,
  3941. dwNameSize,
  3942. pvData,
  3943. dwDataSize,
  3944. pdpnGroupInfo->dwInfoFlags,
  3945. pvAsyncContext,
  3946. pLocalPlayer->GetDPNID(),
  3947. 0,
  3948. &hAsyncOp,
  3949. dwFlags );
  3950. if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
  3951. {
  3952. DPFERR("Could not request host to update info");
  3953. }
  3954. else
  3955. {
  3956. if (!(dwFlags & DPNSETGROUPINFO_SYNC))
  3957. {
  3958. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3959. *phAsyncHandle = hAsyncOp;
  3960. //
  3961. // Release Async HANDLE since this operation has already completed (!)
  3962. //
  3963. // TODO: MASONB: Why does DNHostUpdateInfo do this? This same code is duplicated
  3964. // everywhere.
  3965. CAsyncOp* pAsyncOp;
  3966. if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp )))
  3967. {
  3968. // Release the HandleTable reference
  3969. pAsyncOp->Release();
  3970. pAsyncOp = NULL;
  3971. }
  3972. hAsyncOp = 0;
  3973. }
  3974. }
  3975. }
  3976. else
  3977. {
  3978. DPFX(DPFPREP, 3,"Request host to update group info");
  3979. hResultCode = DNRequestUpdateInfo( pdnObject,
  3980. dpnid,
  3981. pwszName,
  3982. dwNameSize,
  3983. pvData,
  3984. dwDataSize,
  3985. pdpnGroupInfo->dwInfoFlags,
  3986. pvAsyncContext,
  3987. &hAsyncOp,
  3988. dwFlags);
  3989. if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING)
  3990. {
  3991. DPFERR("Could not request host to update info");
  3992. }
  3993. else
  3994. {
  3995. if (!(dwFlags & DPNSETGROUPINFO_SYNC))
  3996. {
  3997. DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp);
  3998. *phAsyncHandle = hAsyncOp;
  3999. }
  4000. }
  4001. }
  4002. pLocalPlayer->Release();
  4003. pLocalPlayer = NULL;
  4004. Exit:
  4005. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  4006. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  4007. return(hResultCode);
  4008. Failure:
  4009. if (pLocalPlayer)
  4010. {
  4011. pLocalPlayer->Release();
  4012. pLocalPlayer = NULL;
  4013. }
  4014. if (pNTEntry)
  4015. {
  4016. pNTEntry->Release();
  4017. pNTEntry = NULL;
  4018. }
  4019. goto Exit;
  4020. }
  4021. // DN_GetGroupInfo
  4022. //
  4023. // Retrieve group name and/or data from the local nametable.
  4024. //
  4025. // lpwszGroupName may be NULL to avoid retrieving group name
  4026. // pdwGroupFlags may be NULL to avoid retrieving group flags
  4027. // pvGroupData may not by NULL if *pdwDataSize is non zero
  4028. #undef DPF_MODNAME
  4029. #define DPF_MODNAME "DN_GetGroupInfo"
  4030. STDMETHODIMP DN_GetGroupInfo(PVOID pv,
  4031. const DPNID dpnid,
  4032. DPN_GROUP_INFO *const pdpnGroupInfo,
  4033. DWORD *const pdwSize,
  4034. const DWORD dwFlags)
  4035. {
  4036. DIRECTNETOBJECT *pdnObject;
  4037. CNameTableEntry *pNTEntry;
  4038. CPackedBuffer packedBuffer;
  4039. HRESULT hResultCode;
  4040. DPFX(DPFPREP, 2,"Parameters: dpnid [0x%lx], pdpnGroupInfo [0x%p], dwFlags [0x%lx]",
  4041. dpnid,pdpnGroupInfo,dwFlags);
  4042. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  4043. DNASSERT(pdnObject != NULL);
  4044. #ifndef DPNBUILD_NOPARAMVAL
  4045. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  4046. {
  4047. if( FAILED( hResultCode = DN_ValidateGetGroupInfo( pv, dpnid, pdpnGroupInfo, pdwSize, dwFlags ) ) )
  4048. {
  4049. DPFERR( "Error validating get group info params" );
  4050. DPF_RETURN( hResultCode );
  4051. }
  4052. }
  4053. #endif // !DPNBUILD_NOPARAMVAL
  4054. // Check to ensure message handler registered
  4055. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  4056. {
  4057. DPFERR( "Object is not initialized" );
  4058. DPF_RETURN(DPNERR_UNINITIALIZED);
  4059. }
  4060. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  4061. {
  4062. DPFERR("Object is connecting / starting to host" );
  4063. DPF_RETURN(DPNERR_CONNECTING);
  4064. }
  4065. if( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING)) )
  4066. {
  4067. DPFERR("You must be connected / hosting to get group info" );
  4068. DPF_RETURN(DPNERR_NOCONNECTION);
  4069. }
  4070. pNTEntry = NULL;
  4071. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  4072. {
  4073. DPFERR( "Specified group is not valid" );
  4074. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  4075. {
  4076. hResultCode = DPNERR_INVALIDGROUP;
  4077. goto Failure;
  4078. }
  4079. }
  4080. packedBuffer.Initialize(pdpnGroupInfo,*pdwSize);
  4081. pNTEntry->Lock();
  4082. if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
  4083. {
  4084. DPFERR( "Specified ID is not a group" );
  4085. pNTEntry->Unlock();
  4086. hResultCode = DPNERR_INVALIDGROUP;
  4087. goto Failure;
  4088. }
  4089. hResultCode = pNTEntry->PackInfo(&packedBuffer);
  4090. pNTEntry->Unlock();
  4091. pNTEntry->Release();
  4092. pNTEntry = NULL;
  4093. if ((hResultCode == DPN_OK) || (hResultCode == DPNERR_BUFFERTOOSMALL))
  4094. {
  4095. *pdwSize = packedBuffer.GetSizeRequired();
  4096. }
  4097. Exit:
  4098. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  4099. return(hResultCode);
  4100. Failure:
  4101. if (pNTEntry)
  4102. {
  4103. pNTEntry->Release();
  4104. pNTEntry = NULL;
  4105. }
  4106. goto Exit;
  4107. }
  4108. #undef DPF_MODNAME
  4109. #define DPF_MODNAME "DN_EnumClientsAndGroups"
  4110. STDMETHODIMP DN_EnumClientsAndGroups(PVOID pInterface,
  4111. DPNID *const prgdpnid,
  4112. DWORD *const pcdpnid,
  4113. const DWORD dwFlags)
  4114. {
  4115. DIRECTNETOBJECT *pdnObject;
  4116. CBilink *pBilink;
  4117. CNameTableEntry *pNTEntry;
  4118. DWORD dwCount;
  4119. DPNID *pDPNID;
  4120. BOOL bEnum = TRUE;
  4121. HRESULT hResultCode;
  4122. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], prgdpnid [0x%p], pcdpnid [0x%p], dwFlags [0x%lx]",
  4123. pInterface,prgdpnid,pcdpnid,dwFlags);
  4124. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  4125. DNASSERT(pdnObject != NULL);
  4126. #ifndef DPNBUILD_NOPARAMVAL
  4127. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  4128. {
  4129. if( FAILED( hResultCode = DN_ValidateEnumClientsAndGroups( pInterface, prgdpnid, pcdpnid, dwFlags ) ) )
  4130. {
  4131. DPFERR( "Error validating enum clients and groups params" );
  4132. DPF_RETURN( hResultCode );
  4133. }
  4134. }
  4135. #endif // !DPNBUILD_NOPARAMVAL
  4136. // Check to ensure message handler registered
  4137. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  4138. {
  4139. DPFERR( "Object is not initialized" );
  4140. DPF_RETURN(DPNERR_UNINITIALIZED);
  4141. }
  4142. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  4143. {
  4144. DPFERR("Object is connecting / starting to host" );
  4145. DPF_RETURN(DPNERR_CONNECTING);
  4146. }
  4147. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  4148. {
  4149. DPFERR("You must be connected / hosting to enumerate players and groups" );
  4150. DPF_RETURN(DPNERR_NOCONNECTION);
  4151. }
  4152. if (prgdpnid == NULL || *pcdpnid == 0) // Don't enum if not asked to
  4153. {
  4154. bEnum = FALSE;
  4155. }
  4156. pdnObject->NameTable.ReadLock();
  4157. dwCount = 0;
  4158. pDPNID = prgdpnid;
  4159. //
  4160. // Enum players
  4161. //
  4162. if (dwFlags & DPNENUM_PLAYERS)
  4163. {
  4164. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  4165. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  4166. {
  4167. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  4168. pNTEntry->Lock();
  4169. if (pNTEntry->IsAvailable())
  4170. {
  4171. dwCount++;
  4172. if (bEnum && (dwCount <= *pcdpnid))
  4173. {
  4174. *pDPNID++ = pNTEntry->GetDPNID();
  4175. }
  4176. else
  4177. {
  4178. bEnum = FALSE;
  4179. }
  4180. }
  4181. pNTEntry->Unlock();
  4182. pBilink = pBilink->GetNext();
  4183. }
  4184. }
  4185. //
  4186. // Enum groups
  4187. //
  4188. if (dwFlags & DPNENUM_GROUPS)
  4189. {
  4190. pBilink = pdnObject->NameTable.m_bilinkGroups.GetNext();
  4191. while (pBilink != &pdnObject->NameTable.m_bilinkGroups)
  4192. {
  4193. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  4194. pNTEntry->Lock();
  4195. if (pNTEntry->IsAvailable() && !pNTEntry->IsAllPlayersGroup())
  4196. {
  4197. dwCount++;
  4198. if (bEnum && (dwCount <= *pcdpnid))
  4199. {
  4200. *pDPNID++ = pNTEntry->GetDPNID();
  4201. }
  4202. else
  4203. {
  4204. bEnum = FALSE;
  4205. }
  4206. }
  4207. pNTEntry->Unlock();
  4208. pBilink = pBilink->GetNext();
  4209. }
  4210. }
  4211. pdnObject->NameTable.Unlock();
  4212. //
  4213. // This will NOT include players/groups in the deleted list.
  4214. // i.e. removed from the NameTable but for whom DESTROY_PLAYER/GROUP notifications have yet to be posted
  4215. //
  4216. *pcdpnid = dwCount;
  4217. if (!bEnum && dwCount)
  4218. {
  4219. hResultCode = DPNERR_BUFFERTOOSMALL;
  4220. }
  4221. else
  4222. {
  4223. hResultCode = DPN_OK;
  4224. }
  4225. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  4226. return(hResultCode);
  4227. }
  4228. #undef DPF_MODNAME
  4229. #define DPF_MODNAME "DN_EnumGroupMembers"
  4230. STDMETHODIMP DN_EnumGroupMembers(PVOID pInterface,
  4231. const DPNID dpnid,
  4232. DPNID *const prgdpnid,
  4233. DWORD *const pcdpnid,
  4234. const DWORD dwFlags)
  4235. {
  4236. DIRECTNETOBJECT *pdnObject;
  4237. CNameTableEntry *pNTEntry;
  4238. CGroupMember *pGroupMember;
  4239. CBilink *pBilink;
  4240. DWORD dwCount;
  4241. DPNID *pDPNID;
  4242. BOOL bOutputBufferTooSmall = FALSE;
  4243. HRESULT hResultCode;
  4244. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnid [0x%lx], prgdpnid [0x%p], pcdpnid [0x%p], dwFlags [0x%lx]",
  4245. pInterface,dpnid,prgdpnid,pcdpnid,dwFlags);
  4246. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  4247. DNASSERT(pdnObject != NULL);
  4248. #ifndef DPNBUILD_NOPARAMVAL
  4249. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  4250. {
  4251. if( FAILED( hResultCode = DN_ValidateEnumGroupMembers( pInterface, dpnid, prgdpnid, pcdpnid, dwFlags ) ) )
  4252. {
  4253. DPFERR( "Error validating enum group params" );
  4254. DPF_RETURN( hResultCode );
  4255. }
  4256. }
  4257. #endif // !DPNBUILD_NOPARAMVAL
  4258. // Check to ensure message handler registered
  4259. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  4260. {
  4261. DPFERR( "Object is not initialized" );
  4262. DPF_RETURN(DPNERR_UNINITIALIZED);
  4263. }
  4264. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  4265. {
  4266. DPFERR("Object is connecting / starting to host" );
  4267. DPF_RETURN(DPNERR_CONNECTING);
  4268. }
  4269. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  4270. {
  4271. DPFERR("You must be connected / hosting to enumerate group members" );
  4272. DPF_RETURN(DPNERR_NOCONNECTION);
  4273. }
  4274. pNTEntry = NULL;
  4275. //
  4276. // if the user didn't supply a buffer, assume that the
  4277. // output buffer is too small
  4278. //
  4279. if ( ( prgdpnid == NULL ) || ( ( *pcdpnid ) == 0 ) )
  4280. {
  4281. bOutputBufferTooSmall = TRUE;
  4282. }
  4283. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  4284. {
  4285. DPFERR("Could not find NameTableEntry");
  4286. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  4287. {
  4288. hResultCode = DPNERR_INVALIDGROUP;
  4289. goto Failure;
  4290. }
  4291. pNTEntry->Release();
  4292. pNTEntry = NULL;
  4293. hResultCode = DPNERR_CONNECTIONLOST;
  4294. goto Failure;
  4295. }
  4296. if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup())
  4297. {
  4298. DPFERR("Not a group dpnid!");
  4299. hResultCode = DPNERR_INVALIDGROUP;
  4300. goto Failure;
  4301. }
  4302. pNTEntry->Lock();
  4303. dwCount = 0;
  4304. pDPNID = prgdpnid;
  4305. pBilink = pNTEntry->m_bilinkMembership.GetNext();
  4306. while (pBilink != &pNTEntry->m_bilinkMembership)
  4307. {
  4308. pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkPlayers);
  4309. dwCount++;
  4310. if ( ( bOutputBufferTooSmall == FALSE ) && (dwCount <= *pcdpnid))
  4311. {
  4312. *pDPNID++ = pGroupMember->GetPlayer()->GetDPNID();
  4313. }
  4314. else
  4315. {
  4316. bOutputBufferTooSmall = TRUE;
  4317. }
  4318. pBilink = pBilink->GetNext();
  4319. }
  4320. pNTEntry->Unlock();
  4321. pNTEntry->Release();
  4322. pNTEntry = NULL;
  4323. *pcdpnid = dwCount;
  4324. //
  4325. // if the user's output buffer appears to be incapable receiving
  4326. // output, double-check to make sure that the output size requirement
  4327. // isn't zero (which is really OK), before telling them that the
  4328. // output buffer is too small
  4329. //
  4330. if ( ( bOutputBufferTooSmall ) && ( dwCount != 0 ) )
  4331. {
  4332. hResultCode = DPNERR_BUFFERTOOSMALL;
  4333. }
  4334. else
  4335. {
  4336. hResultCode = DPN_OK;
  4337. }
  4338. Exit:
  4339. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  4340. return(hResultCode);
  4341. Failure:
  4342. if (pNTEntry)
  4343. {
  4344. pNTEntry->Release();
  4345. pNTEntry = NULL;
  4346. }
  4347. goto Exit;
  4348. }
  4349. #undef DPF_MODNAME
  4350. #define DPF_MODNAME "DN_EnumHosts"
  4351. STDMETHODIMP DN_EnumHosts( PVOID pv,
  4352. DPN_APPLICATION_DESC *const pApplicationDesc,
  4353. IDirectPlay8Address *const pAddrHost,
  4354. IDirectPlay8Address *const pDeviceInfo,
  4355. PVOID const pUserEnumData,
  4356. const DWORD dwUserEnumDataSize,
  4357. const DWORD dwRetryCount,
  4358. const DWORD dwRetryInterval,
  4359. const DWORD dwTimeOut,
  4360. PVOID const pvAsyncContext,
  4361. DPNHANDLE *const pAsyncHandle,
  4362. const DWORD dwFlags )
  4363. {
  4364. DIRECTNETOBJECT *pdnObject;
  4365. HRESULT hResultCode;
  4366. HRESULT hrEnum;
  4367. #ifndef DPNBUILD_ONLYONESP
  4368. GUID guidSP;
  4369. #endif // ! DPNBUILD_ONLYONESP
  4370. #ifndef DPNBUILD_ONLYONEADAPTER
  4371. GUID guidAdapter;
  4372. #endif // ! DPNBUILD_ONLYONEADAPTER
  4373. CAsyncOp *pParent;
  4374. CAsyncOp *pHandleParent;
  4375. CSyncEvent *pSyncEvent;
  4376. CServiceProvider *pSP;
  4377. CRefCountBuffer *pRCBuffer;
  4378. DN_ENUM_QUERY_OP_DATA *pEnumQueryOpData;
  4379. IDirectPlay8Address *pIHost;
  4380. IDirectPlay8Address *pIDevice;
  4381. DPNHANDLE handle;
  4382. DPN_SP_CAPS dnSPCaps;
  4383. #ifndef DPNBUILD_ONLYONEADAPTER
  4384. BOOL fEnumAdapters;
  4385. #endif // ! DPNBUILD_ONLYONEADAPTER
  4386. BOOL fHosting;
  4387. DWORD dwBufferCount;
  4388. DWORD dwEnumQueryFlags;
  4389. DWORD dwMultiplexFlag;
  4390. GUID guidnull;
  4391. #ifdef DBG
  4392. TCHAR DP8ABuffer[512] = {0};
  4393. DWORD DP8ASize;
  4394. #endif // DBG
  4395. DPFX(DPFPREP, 2,"Parameters: pApplicationDesc [0x%p], pAddrHost [0x%p], pDeviceInfo [0x%p], pUserEnumData [0x%p], dwUserEnumDataSize [%ld], dwRetryCount [%ld], dwRetryInterval [%ld], dwTimeOut [%ld], pvAsyncContext [0x%p], pAsyncHandle [0x%p], dwFlags [0x%lx]",
  4396. pApplicationDesc,pAddrHost,pDeviceInfo,pUserEnumData,dwUserEnumDataSize,dwRetryCount,dwRetryInterval,dwTimeOut,pvAsyncContext,pAsyncHandle,dwFlags);
  4397. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  4398. DNASSERT(pdnObject != NULL);
  4399. #ifndef DPNBUILD_NOPARAMVAL
  4400. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  4401. {
  4402. if( FAILED( hResultCode = DN_ValidateEnumHosts( pv, pApplicationDesc, pAddrHost,
  4403. pDeviceInfo, pUserEnumData, dwUserEnumDataSize,
  4404. dwRetryCount, dwRetryInterval, dwTimeOut,
  4405. pvAsyncContext, pAsyncHandle, dwFlags ) ) )
  4406. {
  4407. DPFERR( "Error validating enum hosts params" );
  4408. DPF_RETURN( hResultCode );
  4409. }
  4410. }
  4411. #endif // !DPNBUILD_NOPARAMVAL
  4412. // Check to ensure message handler registered
  4413. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  4414. {
  4415. DPFERR( "Object is not initialized" );
  4416. DPF_RETURN(DPNERR_UNINITIALIZED);
  4417. }
  4418. //
  4419. // initialize
  4420. //
  4421. hResultCode = DPN_OK;
  4422. pParent = NULL;
  4423. pHandleParent = NULL;
  4424. pSyncEvent = NULL;
  4425. pRCBuffer = NULL;
  4426. pSP = NULL;
  4427. pIHost = NULL;
  4428. pIDevice = NULL;
  4429. handle = 0;
  4430. dwMultiplexFlag = 0;
  4431. #ifdef DBG
  4432. if (pAddrHost)
  4433. {
  4434. DP8ASize = 512;
  4435. IDirectPlay8Address_GetURL(pAddrHost,DP8ABuffer,&DP8ASize);
  4436. DPFX(DPFPREP, 4,"Host address [%s]",DP8ABuffer);
  4437. }
  4438. if (pDeviceInfo)
  4439. {
  4440. DP8ASize = 512;
  4441. IDirectPlay8Address_GetURL(pDeviceInfo,DP8ABuffer,&DP8ASize);
  4442. DPFX(DPFPREP, 4,"Device address [%s]",DP8ABuffer);
  4443. }
  4444. #endif // DBG
  4445. //
  4446. // Cannot ENUM if Hosting - I have no idea why, but VanceO insisted on it
  4447. //
  4448. fHosting = FALSE;
  4449. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  4450. if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CONNECTING))
  4451. {
  4452. CNameTableEntry *pLocalPlayer;
  4453. pLocalPlayer = NULL;
  4454. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  4455. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) == DPN_OK)
  4456. {
  4457. if (pLocalPlayer->IsHost())
  4458. {
  4459. fHosting = TRUE;
  4460. }
  4461. pLocalPlayer->Release();
  4462. pLocalPlayer = NULL;
  4463. }
  4464. }
  4465. else
  4466. {
  4467. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  4468. }
  4469. if (fHosting)
  4470. {
  4471. hResultCode = DPNERR_HOSTING;
  4472. goto Failure;
  4473. }
  4474. #if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_LIBINTERFACE)))
  4475. DNASSERT(pdnObject->pOnlySP != NULL);
  4476. pdnObject->pOnlySP->AddRef();
  4477. pSP = pdnObject->pOnlySP;
  4478. #else // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
  4479. #ifndef DPNBUILD_ONLYONESP
  4480. //
  4481. // Extract SP guid as we will probably need it
  4482. //
  4483. hResultCode = IDirectPlay8Address_GetSP(pDeviceInfo,&guidSP);
  4484. if ( hResultCode != DPN_OK)
  4485. {
  4486. DPFERR("SP not specified in Device address");
  4487. goto Failure;
  4488. }
  4489. #endif // ! DPNBUILD_ONLYONESP
  4490. //
  4491. // Ensure SP specified in Device address is loaded
  4492. //
  4493. hResultCode = DN_SPEnsureLoaded(pdnObject,
  4494. #ifndef DPNBUILD_ONLYONESP
  4495. &guidSP,
  4496. #endif // ! DPNBUILD_ONLYONESP
  4497. #ifndef DPNBUILD_LIBINTERFACE
  4498. NULL,
  4499. #endif // ! DPNBUILD_LIBINTERFACE
  4500. &pSP);
  4501. if (hResultCode != DPN_OK)
  4502. {
  4503. DPFERR("Could not ensure SP is loaded!");
  4504. DisplayDNError(0,hResultCode);
  4505. goto Failure;
  4506. }
  4507. #endif // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
  4508. //
  4509. // Get SP caps to ensure payload will fit
  4510. //
  4511. if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) != DPN_OK)
  4512. {
  4513. DPFERR("Could not get SP caps");
  4514. DisplayDNError(0,hResultCode);
  4515. goto Failure;
  4516. }
  4517. //
  4518. // Ensure payload will fit
  4519. //
  4520. if (dwUserEnumDataSize > dnSPCaps.dwMaxEnumPayloadSize)
  4521. {
  4522. DPFERR("User enum data is too large");
  4523. hResultCode = DPNERR_ENUMQUERYTOOLARGE;
  4524. goto Failure;
  4525. }
  4526. //
  4527. // Duplicate addresses for local usage (so we can modify them if neccessary
  4528. //
  4529. if (pAddrHost)
  4530. {
  4531. // Use supplied Host address
  4532. if ((hResultCode = IDirectPlay8Address_Duplicate(pAddrHost,&pIHost)) != DPN_OK)
  4533. {
  4534. DPFERR("Could not duplicate Host address");
  4535. DisplayDNError(0,hResultCode);
  4536. hResultCode = DPNERR_INVALIDHOSTADDRESS;
  4537. goto Failure;
  4538. }
  4539. }
  4540. else
  4541. {
  4542. //
  4543. // Create new Host address and use Device SP guid
  4544. //
  4545. #ifdef DPNBUILD_LIBINTERFACE
  4546. hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
  4547. reinterpret_cast<void**>(&pIHost));
  4548. #else // ! DPNBUILD_LIBINTERFACE
  4549. hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
  4550. NULL,
  4551. CLSCTX_INPROC_SERVER,
  4552. IID_IDirectPlay8Address,
  4553. reinterpret_cast<void**>(&pIHost),
  4554. FALSE);
  4555. #endif // ! DPNBUILD_LIBINTERFACE
  4556. if (hResultCode != S_OK)
  4557. {
  4558. DPFERR("Could not create Host address");
  4559. DisplayDNError(0,hResultCode);
  4560. DNASSERT(FALSE);
  4561. goto Failure;
  4562. }
  4563. #ifndef DPNBUILD_ONLYONESP
  4564. if ((hResultCode = IDirectPlay8Address_SetSP(pIHost,&guidSP)) != DPN_OK)
  4565. {
  4566. DPFERR("Could not set Host address SP");
  4567. DisplayDNError(0,hResultCode);
  4568. DNASSERT(FALSE);
  4569. goto Failure;
  4570. }
  4571. #endif // ! DPNBUILD_ONLYONESP
  4572. }
  4573. #if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_ONLYONEADAPTER)))
  4574. if (pDeviceInfo == NULL)
  4575. {
  4576. hResultCode = IDirectPlay8Address_Duplicate(pIHost,&pIDevice);
  4577. }
  4578. else
  4579. #endif // DPNBUILD_ONLYONESP and DPNBUILD_ONLYONEADAPTER
  4580. {
  4581. hResultCode = IDirectPlay8Address_Duplicate(pDeviceInfo,&pIDevice);
  4582. }
  4583. if (hResultCode != DPN_OK)
  4584. {
  4585. DPFERR("Could not duplicate Device address");
  4586. DisplayDNError(0,hResultCode);
  4587. DNASSERT(FALSE);
  4588. goto Failure;
  4589. }
  4590. #ifdef DBG
  4591. DP8ASize = 512;
  4592. IDirectPlay8Address_GetURL(pIHost,DP8ABuffer,&DP8ASize);
  4593. DPFX(DPFPREP, 4,"Host address [%s]",DP8ABuffer);
  4594. DP8ASize = 512;
  4595. IDirectPlay8Address_GetURL(pIDevice,DP8ABuffer,&DP8ASize);
  4596. DPFX(DPFPREP, 4,"Device address [%s]",DP8ABuffer);
  4597. #endif // DBG
  4598. // Enum flags to Protocol
  4599. dwEnumQueryFlags = 0;
  4600. #ifndef DPNBUILD_NOSPUI
  4601. if (dwFlags & DPNENUMHOSTS_OKTOQUERYFORADDRESSING)
  4602. {
  4603. dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_OKTOQUERYFORADDRESSING;
  4604. }
  4605. #endif // ! DPNBUILD_NOSPUI
  4606. if (dwFlags & DPNENUMHOSTS_NOBROADCASTFALLBACK)
  4607. {
  4608. dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_NOBROADCASTFALLBACK;
  4609. }
  4610. if (pApplicationDesc->dwReservedDataSize > 0)
  4611. {
  4612. dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_SESSIONDATA;
  4613. }
  4614. //
  4615. // Parent for ENUMs
  4616. //
  4617. if ((hResultCode = AsyncOpNew(pdnObject,&pParent)) != DPN_OK)
  4618. {
  4619. DPFERR("Could not create ENUM parent AsyncOp");
  4620. DisplayDNError(0,hResultCode);
  4621. DNASSERT(FALSE);
  4622. goto Failure;
  4623. }
  4624. pParent->MakeParent();
  4625. pParent->SetOpType( ASYNC_OP_ENUM_QUERY );
  4626. pParent->SetContext( pvAsyncContext );
  4627. pParent->SetCompletion( DNCompleteEnumQuery );
  4628. pParent->SetOpFlags( dwEnumQueryFlags );
  4629. //
  4630. // Synchronous ?
  4631. //
  4632. if (dwFlags & DPNENUMHOSTS_SYNC)
  4633. {
  4634. if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
  4635. {
  4636. DPFERR("Could not create SyncEvent");
  4637. DisplayDNError(0,hResultCode);
  4638. DNASSERT(FALSE);
  4639. goto Failure;
  4640. }
  4641. pParent->SetSyncEvent( pSyncEvent );
  4642. pParent->SetResultPointer( &hrEnum );
  4643. hrEnum = DPNERR_GENERIC;
  4644. }
  4645. else
  4646. {
  4647. //
  4648. // Create Handle parent AsyncOp (if required)
  4649. //
  4650. if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK)
  4651. {
  4652. DPFERR("Could not create AsyncOp");
  4653. DisplayDNError(0,hResultCode);
  4654. DNASSERT(FALSE);
  4655. goto Failure;
  4656. }
  4657. pHandleParent->SetContext( pvAsyncContext );
  4658. pHandleParent->Lock();
  4659. if (pHandleParent->IsCancelled())
  4660. {
  4661. pHandleParent->Unlock();
  4662. pParent->SetResult( DPNERR_USERCANCEL );
  4663. hResultCode = DPNERR_USERCANCEL;
  4664. goto Failure;
  4665. }
  4666. pParent->MakeChild( pHandleParent );
  4667. handle = pHandleParent->GetHandle();
  4668. pHandleParent->Unlock();
  4669. }
  4670. //
  4671. // Keep SP on ENUM parent
  4672. //
  4673. pParent->SetSP( pSP );
  4674. pSP->Release();
  4675. pSP = NULL;
  4676. pEnumQueryOpData = pParent->GetLocalEnumQueryOpData();
  4677. #ifndef DPNBUILD_ONLYONEADAPTER
  4678. //
  4679. // If there is no adapter specified in the device address,
  4680. // we will attempt to enum on each individual adapter if the SP supports it
  4681. //
  4682. fEnumAdapters = FALSE;
  4683. if ((hResultCode = IDirectPlay8Address_GetDevice( pIDevice, &guidAdapter )) != DPN_OK)
  4684. {
  4685. DPFX(DPFPREP,1,"Could not determine adapter");
  4686. DisplayDNError(1,hResultCode);
  4687. if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSALLADAPTERS)
  4688. {
  4689. DPFX(DPFPREP, 3,"SP supports ENUMing on all adapters");
  4690. fEnumAdapters = TRUE;
  4691. }
  4692. }
  4693. if(fEnumAdapters)
  4694. {
  4695. DWORD dwNumAdapters;
  4696. GUID *pAdapterList = NULL;
  4697. if ((hResultCode = DNEnumAdapterGuids( pdnObject,
  4698. #ifndef DPNBUILD_ONLYONESP
  4699. &guidSP,
  4700. #endif // ! DPNBUILD_ONLYONESP
  4701. 0,
  4702. &pAdapterList,
  4703. &dwNumAdapters)) != DPN_OK)
  4704. {
  4705. DPFERR("Could not enum adapters for this SP");
  4706. DisplayDNError(0,hResultCode);
  4707. goto Failure;
  4708. }
  4709. if (dwNumAdapters == 0)
  4710. {
  4711. DPFERR("No adapters were found for this SP");
  4712. hResultCode = DPNERR_INVALIDDEVICEADDRESS;
  4713. goto Failure;
  4714. }
  4715. pEnumQueryOpData->dwNumAdapters = dwNumAdapters;
  4716. pEnumQueryOpData->dwCurrentAdapter = 0;
  4717. if (dwNumAdapters > 1)
  4718. {
  4719. dwMultiplexFlag |= DN_ENUMQUERYFLAGS_ADDITIONALMULTIPLEXADAPTERS;
  4720. }
  4721. //
  4722. // Choose first adapter for initial ENUM call
  4723. //
  4724. if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice,pAdapterList)) != DPN_OK)
  4725. {
  4726. DPFERR("Could not set device adapter");
  4727. DisplayDNError(0,hResultCode);
  4728. MemoryBlockFree(pdnObject,pAdapterList);
  4729. goto Failure;
  4730. }
  4731. pEnumQueryOpData->dwCurrentAdapter++;
  4732. pParent->SetOpData( pAdapterList );
  4733. pAdapterList = NULL;
  4734. }
  4735. else
  4736. #endif // ! DPNBUILD_ONLYONEADAPTER
  4737. {
  4738. #ifndef DPNBUILD_ONLYONEADAPTER
  4739. pEnumQueryOpData->dwNumAdapters = 0;
  4740. pEnumQueryOpData->dwCurrentAdapter = 0;
  4741. #endif // ! DPNBUILD_ONLYONEADAPTER
  4742. }
  4743. //
  4744. // Set up EnumQuery BufferDescriptions
  4745. //
  4746. //
  4747. // When filling out the enum structure the SP requires an extra BUFFERDESC
  4748. // to exist immediately before the one were passing with the user data. The
  4749. // SP will be using that extra buffer to prepend an optional header
  4750. //
  4751. pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].pBufferData = reinterpret_cast<BYTE*>(&pEnumQueryOpData->EnumQueryPayload);
  4752. memset(&guidnull, 0, sizeof(guidnull));
  4753. if (pApplicationDesc->guidApplication != guidnull)
  4754. {
  4755. DPFX(DPFPREP, 7, "Object 0x%p enumerating with application GUID {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}.",
  4756. pdnObject,
  4757. pApplicationDesc->guidApplication.Data1,
  4758. pApplicationDesc->guidApplication.Data2,
  4759. pApplicationDesc->guidApplication.Data3,
  4760. pApplicationDesc->guidApplication.Data4[0],
  4761. pApplicationDesc->guidApplication.Data4[1],
  4762. pApplicationDesc->guidApplication.Data4[2],
  4763. pApplicationDesc->guidApplication.Data4[3],
  4764. pApplicationDesc->guidApplication.Data4[4],
  4765. pApplicationDesc->guidApplication.Data4[5],
  4766. pApplicationDesc->guidApplication.Data4[6],
  4767. pApplicationDesc->guidApplication.Data4[7]);
  4768. pEnumQueryOpData->EnumQueryPayload.QueryType = DN_ENUM_QUERY_WITH_APPLICATION_GUID;
  4769. memcpy(&pEnumQueryOpData->EnumQueryPayload.guidApplication,&pApplicationDesc->guidApplication,sizeof(GUID));
  4770. pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].dwBufferSize = sizeof(DN_ENUM_QUERY_PAYLOAD);
  4771. }
  4772. else
  4773. {
  4774. pEnumQueryOpData->EnumQueryPayload.QueryType = DN_ENUM_QUERY_WITHOUT_APPLICATION_GUID;
  4775. pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].dwBufferSize = sizeof(DN_ENUM_QUERY_PAYLOAD) - sizeof(GUID);
  4776. }
  4777. //
  4778. // Copy user data (if any)
  4779. //
  4780. if (pUserEnumData && dwUserEnumDataSize)
  4781. {
  4782. DPFX(DPFPREP,3,"User enum data specified");
  4783. if ((hResultCode = RefCountBufferNew(pdnObject,dwUserEnumDataSize,MemoryBlockAlloc,MemoryBlockFree,&pRCBuffer)) != DPN_OK)
  4784. {
  4785. DPFERR("Could not create RefCountBuffer");
  4786. DisplayDNError(0,hResultCode);
  4787. goto Failure;
  4788. }
  4789. memcpy(pRCBuffer->GetBufferAddress(),pUserEnumData,dwUserEnumDataSize);
  4790. pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].pBufferData = reinterpret_cast<BYTE*>(pRCBuffer->GetBufferAddress());
  4791. pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].dwBufferSize = dwUserEnumDataSize;
  4792. pParent->SetRefCountBuffer( pRCBuffer );
  4793. dwBufferCount = DN_ENUM_BUFFERDESC_QUERY_COUNT;
  4794. pRCBuffer->Release();
  4795. pRCBuffer = NULL;
  4796. }
  4797. else
  4798. {
  4799. DPFX(DPFPREP,3,"User enum data not specified");
  4800. pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].pBufferData = NULL;
  4801. pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].dwBufferSize = 0;
  4802. dwBufferCount = DN_ENUM_BUFFERDESC_QUERY_COUNT - 1;
  4803. }
  4804. //
  4805. // Set up EnumQuery misc fields
  4806. //
  4807. pEnumQueryOpData->dwRetryCount = dwRetryCount;
  4808. pEnumQueryOpData->dwRetryInterval = dwRetryInterval;
  4809. pEnumQueryOpData->dwTimeOut = dwTimeOut;
  4810. pEnumQueryOpData->dwBufferCount = dwBufferCount;
  4811. //
  4812. // For reserved data we understand, we don't actually need all of the data we had the
  4813. // user track.
  4814. //
  4815. if ((pApplicationDesc->dwReservedDataSize == DPN_MAX_APPDESC_RESERVEDDATA_SIZE) &&
  4816. (*((DWORD*) pApplicationDesc->pvReservedData) == SPSESSIONDATAINFO_XNET))
  4817. {
  4818. pEnumQueryOpData->dwAppDescReservedDataSize = sizeof(SPSESSIONDATA_XNET);
  4819. memcpy(pEnumQueryOpData->AppDescReservedData, &pApplicationDesc->pvReservedData, pEnumQueryOpData->dwAppDescReservedDataSize);
  4820. }
  4821. else
  4822. {
  4823. pEnumQueryOpData->dwAppDescReservedDataSize = 0;
  4824. }
  4825. DPFX(DPFPREP,3,"Number of buffers actually used [%ld]",dwBufferCount);
  4826. hResultCode = DNPerformEnumQuery( pdnObject,
  4827. pIHost,
  4828. pIDevice,
  4829. pParent->GetSP()->GetHandle(),
  4830. pParent->GetOpFlags() | dwMultiplexFlag,
  4831. pParent->GetContext(),
  4832. pParent );
  4833. if (hResultCode != DPN_OK)
  4834. {
  4835. DPFERR("Could not start ENUM");
  4836. DisplayDNError(0,hResultCode);
  4837. goto Failure;
  4838. }
  4839. pParent->Release();
  4840. pParent = NULL;
  4841. //
  4842. // Wait for SyncEvent or return Async Handle
  4843. //
  4844. if (dwFlags & DPNENUMHOSTS_SYNC)
  4845. {
  4846. pSyncEvent->WaitForEvent();
  4847. pSyncEvent->ReturnSelfToPool();
  4848. pSyncEvent = NULL;
  4849. hResultCode = hrEnum;
  4850. }
  4851. else
  4852. {
  4853. //
  4854. // Blame vanceo if this EVER returns anything other than DPN_OK at this stage
  4855. //
  4856. pHandleParent->SetCompletion( DNCompleteAsyncHandle );
  4857. pHandleParent->Release();
  4858. pHandleParent = NULL;
  4859. *pAsyncHandle = handle;
  4860. hResultCode = DPNERR_PENDING;
  4861. }
  4862. IDirectPlay8Address_Release(pIDevice);
  4863. pIDevice = NULL;
  4864. IDirectPlay8Address_Release(pIHost);
  4865. pIHost = NULL;
  4866. Exit:
  4867. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  4868. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  4869. return(hResultCode);
  4870. Failure:
  4871. if (handle != 0)
  4872. {
  4873. CAsyncOp* pAsyncOp;
  4874. if (SUCCEEDED(pdnObject->HandleTable.Destroy( handle, (PVOID*)&pAsyncOp )))
  4875. {
  4876. // Release the HandleTable reference
  4877. pAsyncOp->Release();
  4878. pAsyncOp = NULL;
  4879. }
  4880. handle = 0;
  4881. }
  4882. if (pParent)
  4883. {
  4884. pParent->Release();
  4885. pParent = NULL;
  4886. }
  4887. if (pHandleParent)
  4888. {
  4889. pHandleParent->Release();
  4890. pHandleParent = NULL;
  4891. }
  4892. if (pSyncEvent)
  4893. {
  4894. pSyncEvent->ReturnSelfToPool();
  4895. pSyncEvent = NULL;
  4896. }
  4897. if (pRCBuffer)
  4898. {
  4899. pRCBuffer->Release();
  4900. pRCBuffer = NULL;
  4901. }
  4902. if (pSP)
  4903. {
  4904. pSP->Release();
  4905. pSP = NULL;
  4906. }
  4907. if (pIHost)
  4908. {
  4909. IDirectPlay8Address_Release(pIHost);
  4910. pIHost = NULL;
  4911. }
  4912. if (pIDevice)
  4913. {
  4914. IDirectPlay8Address_Release(pIDevice);
  4915. pIDevice = NULL;
  4916. }
  4917. goto Exit;
  4918. }
  4919. //**********************************************************************
  4920. // DN_DestroyPlayer
  4921. //
  4922. // Remove a player from this DirectNet session
  4923. // This will send a termination message to the player.
  4924. // Both the host and the player will terminate.
  4925. #undef DPF_MODNAME
  4926. #define DPF_MODNAME "DN_DestroyPlayer"
  4927. STDMETHODIMP DN_DestroyPlayer(PVOID pInterface,
  4928. const DPNID dpnid,
  4929. const void *const pvDestroyData,
  4930. const DWORD dwDestroyDataSize,
  4931. const DWORD dwFlags)
  4932. {
  4933. DIRECTNETOBJECT *pdnObject;
  4934. HRESULT hResultCode;
  4935. CRefCountBuffer *pRefCountBuffer;
  4936. CNameTableEntry *pNTEntry;
  4937. CConnection *pConnection;
  4938. DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
  4939. DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], dpnid [0x%lx], pvDestroyData [0x%p], dwDestroyDataSize [%ld], dwFlags [0x%lx]",
  4940. pInterface,dpnid,pvDestroyData,dwDestroyDataSize,dwFlags);
  4941. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  4942. DNASSERT(pdnObject != NULL);
  4943. #ifndef DPNBUILD_NOPARAMVAL
  4944. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  4945. {
  4946. if( FAILED( hResultCode = DN_ValidateDestroyPlayer( pInterface, dpnid, pvDestroyData, dwDestroyDataSize, dwFlags ) ) )
  4947. {
  4948. DPFERR( "Error validating destroy player params" );
  4949. DPF_RETURN( hResultCode );
  4950. }
  4951. }
  4952. #endif // !DPNBUILD_NOPARAMVAL
  4953. // Check to ensure message handler registered
  4954. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  4955. {
  4956. DPFERR( "Object is not initialized" );
  4957. DPF_RETURN(DPNERR_UNINITIALIZED);
  4958. }
  4959. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  4960. {
  4961. DPFERR("Object is connecting / starting to host" );
  4962. DPF_RETURN(DPNERR_CONNECTING);
  4963. }
  4964. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  4965. {
  4966. DPFERR("You must be connected / hosting to destroy a player" );
  4967. DPF_RETURN(DPNERR_NOCONNECTION);
  4968. }
  4969. pNTEntry = NULL;
  4970. pRefCountBuffer = NULL;
  4971. pConnection = NULL;
  4972. if (!DN_CHECK_LOCALHOST(pdnObject))
  4973. {
  4974. DPFERR( "Object is not session host, cannot destroy players" );
  4975. DPF_RETURN(DPNERR_NOTHOST);
  4976. }
  4977. // Ensure DNID specified is valid
  4978. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  4979. {
  4980. DPFERR("Could not find player entry");
  4981. DisplayDNError(0,hResultCode);
  4982. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  4983. {
  4984. hResultCode = DPNERR_INVALIDPLAYER;
  4985. goto Failure;
  4986. }
  4987. pNTEntry->Release();
  4988. pNTEntry = NULL;
  4989. hResultCode = DPNERR_CONNECTIONLOST;
  4990. goto Failure;
  4991. }
  4992. if (pNTEntry->IsLocal() )
  4993. {
  4994. DPFERR( "Cannot destroy local player" );
  4995. hResultCode = DPNERR_INVALIDPLAYER;
  4996. DisplayDNError(0,hResultCode);
  4997. goto Failure;
  4998. }
  4999. if (pNTEntry->IsGroup())
  5000. {
  5001. hResultCode = DPNERR_INVALIDPLAYER;
  5002. goto Failure;
  5003. }
  5004. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK)
  5005. {
  5006. DPFERR("Could not get connection ref");
  5007. DisplayDNError(0,hResultCode);
  5008. hResultCode = DPNERR_CONNECTIONLOST;
  5009. goto Failure;
  5010. }
  5011. pNTEntry->Release();
  5012. pNTEntry = NULL;
  5013. //
  5014. // Build terminate message
  5015. //
  5016. hResultCode = RefCountBufferNew(pdnObject,
  5017. sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION) + dwDestroyDataSize,
  5018. MemoryBlockAlloc,
  5019. MemoryBlockFree,
  5020. &pRefCountBuffer);
  5021. if (hResultCode != DPN_OK)
  5022. {
  5023. DPFERR("Could not allocate RefCountBuffer");
  5024. DisplayDNError(0,hResultCode);
  5025. goto Failure;
  5026. }
  5027. pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pRefCountBuffer->GetBufferAddress());
  5028. if (dwDestroyDataSize)
  5029. {
  5030. memcpy(pMsg+1,pvDestroyData,dwDestroyDataSize);
  5031. pMsg->dwTerminateDataOffset = sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION);
  5032. }
  5033. else
  5034. {
  5035. pMsg->dwTerminateDataOffset = 0;
  5036. }
  5037. pMsg->dwTerminateDataSize = dwDestroyDataSize;
  5038. //
  5039. // Send message to player to exit
  5040. //
  5041. hResultCode = DNSendMessage(pdnObject,
  5042. pConnection,
  5043. DN_MSG_INTERNAL_TERMINATE_SESSION,
  5044. dpnid,
  5045. pRefCountBuffer->BufferDescAddress(),
  5046. 1,
  5047. pRefCountBuffer,
  5048. 0,
  5049. DN_SENDFLAGS_RELIABLE,
  5050. NULL,
  5051. NULL);
  5052. if (hResultCode != DPNERR_PENDING)
  5053. {
  5054. DPFERR("Could not send DESTROY_CLIENT message to player");
  5055. DisplayDNError(0,hResultCode);
  5056. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  5057. if (hResultCode == DPNERR_INVALIDENDPOINT)
  5058. {
  5059. hResultCode = DPNERR_INVALIDPLAYER;
  5060. }
  5061. goto Failure;
  5062. }
  5063. pConnection->Release();
  5064. pConnection = NULL;
  5065. pRefCountBuffer->Release();
  5066. pRefCountBuffer = NULL;
  5067. //
  5068. // Remove from NameTable and inform other players of disconnect
  5069. //
  5070. hResultCode = DNHostDisconnect(pdnObject,dpnid,DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
  5071. hResultCode = DPN_OK;
  5072. Exit:
  5073. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  5074. DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
  5075. return(hResultCode);
  5076. Failure:
  5077. if (pNTEntry)
  5078. {
  5079. pNTEntry->Release();
  5080. pNTEntry = NULL;
  5081. }
  5082. if (pConnection)
  5083. {
  5084. pConnection->Release();
  5085. pConnection = NULL;
  5086. }
  5087. if (pRefCountBuffer)
  5088. {
  5089. pRefCountBuffer->Release();
  5090. pRefCountBuffer = NULL;
  5091. }
  5092. goto Exit;
  5093. }
  5094. // DN_ReturnBuffer
  5095. //
  5096. // Return a receive buffer which is no longer in use
  5097. #undef DPF_MODNAME
  5098. #define DPF_MODNAME "DN_ReturnBuffer"
  5099. STDMETHODIMP DN_ReturnBuffer(PVOID pv,
  5100. const DPNHANDLE hBufferHandle,
  5101. const DWORD dwFlags)
  5102. {
  5103. DIRECTNETOBJECT *pdnObject;
  5104. HRESULT hResultCode;
  5105. CAsyncOp *pAsyncOp;
  5106. DPFX(DPFPREP, 2,"Parameters: hBufferHandle [0x%lx], dwFlags [0x%lx]",hBufferHandle,dwFlags);
  5107. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  5108. DNASSERT(pdnObject != NULL);
  5109. #ifndef DPNBUILD_NOPARAMVAL
  5110. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  5111. {
  5112. if( FAILED( hResultCode = DN_ValidateReturnBuffer( pv, hBufferHandle, dwFlags ) ) )
  5113. {
  5114. DPFERR( "Error validating return buffer params" );
  5115. DPF_RETURN( hResultCode );
  5116. }
  5117. }
  5118. #endif // !DPNBUILD_NOPARAMVAL
  5119. // Check to ensure message handler registered
  5120. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  5121. {
  5122. DPFERR( "Object is not initialized" );
  5123. DPF_RETURN(DPNERR_UNINITIALIZED);
  5124. }
  5125. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  5126. {
  5127. DPFERR("Object is connecting / starting to host" );
  5128. DPF_RETURN(DPNERR_CONNECTING);
  5129. }
  5130. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  5131. {
  5132. DPFERR("You must be connected / hosting to return a buffer" );
  5133. DPF_RETURN(DPNERR_NOCONNECTION);
  5134. }
  5135. DNASSERT( pdnObject != NULL );
  5136. pAsyncOp = NULL;
  5137. //
  5138. // Find async op
  5139. //
  5140. pdnObject->HandleTable.Lock();
  5141. if ((hResultCode = pdnObject->HandleTable.Find( hBufferHandle,(PVOID*)&pAsyncOp )) != DPN_OK)
  5142. {
  5143. pdnObject->HandleTable.Unlock();
  5144. DPFERR("Could not find handle");
  5145. DisplayDNError(0,hResultCode);
  5146. hResultCode = DPNERR_INVALIDHANDLE;
  5147. goto Failure;
  5148. }
  5149. else
  5150. {
  5151. pAsyncOp->AddRef();
  5152. pdnObject->HandleTable.Unlock();
  5153. }
  5154. //
  5155. // Ensure it's not already cancelled
  5156. //
  5157. pAsyncOp->Lock();
  5158. if (pAsyncOp->IsCancelled() || pAsyncOp->IsComplete())
  5159. {
  5160. pAsyncOp->Unlock();
  5161. hResultCode = DPNERR_INVALIDHANDLE;
  5162. goto Failure;
  5163. }
  5164. pAsyncOp->SetComplete();
  5165. pAsyncOp->Unlock();
  5166. if (SUCCEEDED(pdnObject->HandleTable.Destroy( hBufferHandle, NULL )))
  5167. {
  5168. //
  5169. // Remove from active list
  5170. //
  5171. DNEnterCriticalSection(&pdnObject->csActiveList);
  5172. pAsyncOp->m_bilinkActiveList.RemoveFromList();
  5173. DNLeaveCriticalSection(&pdnObject->csActiveList);
  5174. // Release the HandleTable reference
  5175. pAsyncOp->Release();
  5176. }
  5177. pAsyncOp->Release();
  5178. pAsyncOp = NULL;
  5179. Exit:
  5180. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  5181. return(hResultCode);
  5182. Failure:
  5183. if (pAsyncOp)
  5184. {
  5185. pAsyncOp->Release();
  5186. pAsyncOp = NULL;
  5187. }
  5188. goto Exit;
  5189. }
  5190. // DN_GetPlayerContext
  5191. #undef DPF_MODNAME
  5192. #define DPF_MODNAME "DN_GetPlayerContext"
  5193. STDMETHODIMP DN_GetPlayerContext(PVOID pv,
  5194. const DPNID dpnid,
  5195. PVOID *const ppvPlayerContext,
  5196. const DWORD dwFlags)
  5197. {
  5198. HRESULT hResultCode;
  5199. CNameTableEntry *pNTEntry;
  5200. DIRECTNETOBJECT *pdnObject;
  5201. DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], ppvPlayerContext [0x%p], dwFlags [0x%lx]",
  5202. pv, dpnid,ppvPlayerContext,dwFlags);
  5203. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  5204. DNASSERT(pdnObject != NULL);
  5205. #ifndef DPNBUILD_NOPARAMVAL
  5206. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  5207. {
  5208. if( FAILED( hResultCode = DN_ValidateGetPlayerContext( pv, dpnid, ppvPlayerContext, dwFlags ) ) )
  5209. {
  5210. DPFERR( "Error validating getplayercontext params" );
  5211. DPF_RETURN( hResultCode );
  5212. }
  5213. }
  5214. #endif // !DPNBUILD_NOPARAMVAL
  5215. // Check to ensure message handler registered
  5216. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  5217. {
  5218. DPFERR( "Object is not initialized" );
  5219. DPF_RETURN(DPNERR_UNINITIALIZED);
  5220. }
  5221. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  5222. {
  5223. DPFERR("Object is connecting / starting to host" );
  5224. DPF_RETURN(DPNERR_CONNECTING);
  5225. }
  5226. if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) )
  5227. {
  5228. DPFERR("You must be connected / hosting to get player context" );
  5229. DPF_RETURN(DPNERR_NOCONNECTION);
  5230. }
  5231. pNTEntry = NULL;
  5232. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  5233. {
  5234. DPFERR("Could not retrieve player entry");
  5235. DisplayDNError(0,hResultCode);
  5236. //
  5237. // Try deleted list
  5238. //
  5239. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  5240. {
  5241. DPFERR("Could not find player in deleted list either");
  5242. DisplayDNError(0,hResultCode);
  5243. hResultCode = DPNERR_INVALIDPLAYER;
  5244. goto Failure;
  5245. }
  5246. }
  5247. //
  5248. // Ensure this is not a group and that the player has been created
  5249. // There may be a period during which the player is "available" but the CREATE_PLAYER notification
  5250. // has not returned. Return DPNERR_NOTREADY in this case.
  5251. //
  5252. pNTEntry->Lock();
  5253. if (pNTEntry->IsGroup())
  5254. {
  5255. pNTEntry->Unlock();
  5256. hResultCode = DPNERR_INVALIDPLAYER;
  5257. goto Failure;
  5258. }
  5259. if (!pNTEntry->IsCreated())
  5260. {
  5261. if (pNTEntry->IsAvailable())
  5262. {
  5263. hResultCode = DPNERR_NOTREADY;
  5264. }
  5265. else
  5266. {
  5267. hResultCode = DPNERR_INVALIDPLAYER;
  5268. }
  5269. pNTEntry->Unlock();
  5270. goto Failure;
  5271. }
  5272. *ppvPlayerContext = pNTEntry->GetContext();
  5273. pNTEntry->Unlock();
  5274. pNTEntry->Release();
  5275. pNTEntry = NULL;
  5276. hResultCode = DPN_OK;
  5277. Exit:
  5278. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  5279. return(hResultCode);
  5280. Failure:
  5281. if (pNTEntry)
  5282. {
  5283. pNTEntry->Release();
  5284. pNTEntry = NULL;
  5285. }
  5286. goto Exit;
  5287. }
  5288. // DN_GetGroupContext
  5289. #undef DPF_MODNAME
  5290. #define DPF_MODNAME "DN_GetGroupContext"
  5291. STDMETHODIMP DN_GetGroupContext(PVOID pv,
  5292. const DPNID dpnid,
  5293. PVOID *const ppvGroupContext,
  5294. const DWORD dwFlags)
  5295. {
  5296. HRESULT hResultCode;
  5297. CNameTableEntry *pNTEntry;
  5298. DIRECTNETOBJECT *pdnObject;
  5299. DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], ppvGroupContext [0x%p], dwFlags [0x%lx]",
  5300. pv, dpnid,ppvGroupContext,dwFlags);
  5301. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv));
  5302. DNASSERT(pdnObject != NULL);
  5303. #ifndef DPNBUILD_NOPARAMVAL
  5304. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  5305. {
  5306. if( FAILED( hResultCode = DN_ValidateGetGroupContext( pv, dpnid, ppvGroupContext,dwFlags ) ) )
  5307. {
  5308. DPFERR( "Error validating getgroupcontext params" );
  5309. DPF_RETURN( hResultCode );
  5310. }
  5311. }
  5312. #endif // !DPNBUILD_NOPARAMVAL
  5313. // Check to ensure message handler registered
  5314. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  5315. {
  5316. DPFERR( "Object is not initialized" );
  5317. DPF_RETURN(DPNERR_UNINITIALIZED);
  5318. }
  5319. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  5320. {
  5321. DPFERR("Object is connecting / starting to host" );
  5322. DPF_RETURN(DPNERR_CONNECTING);
  5323. }
  5324. if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) )
  5325. {
  5326. DPFERR("You must be connected / hosting to get group context" );
  5327. DPF_RETURN(DPNERR_NOCONNECTION);
  5328. }
  5329. pNTEntry = NULL;
  5330. if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  5331. {
  5332. DPFERR("Could not retrieve group entry");
  5333. DisplayDNError(0,hResultCode);
  5334. //
  5335. // Try deleted list
  5336. //
  5337. if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK)
  5338. {
  5339. DPFERR("Could not find player in deleted list either");
  5340. DisplayDNError(0,hResultCode);
  5341. hResultCode = DPNERR_INVALIDGROUP;
  5342. goto Failure;
  5343. }
  5344. }
  5345. //
  5346. // Ensure this is not a player and that the group has been created
  5347. // There may be a period during which the group is "available" but the CREATE_GROUP notification
  5348. // has not returned. Return DPNERR_NOTREADY in this case.
  5349. //
  5350. pNTEntry->Lock();
  5351. if (!pNTEntry->IsGroup())
  5352. {
  5353. pNTEntry->Unlock();
  5354. hResultCode = DPNERR_INVALIDGROUP;
  5355. goto Failure;
  5356. }
  5357. if (!pNTEntry->IsCreated())
  5358. {
  5359. if (pNTEntry->IsAvailable())
  5360. {
  5361. hResultCode = DPNERR_NOTREADY;
  5362. }
  5363. else
  5364. {
  5365. hResultCode = DPNERR_INVALIDGROUP;
  5366. }
  5367. pNTEntry->Unlock();
  5368. goto Failure;
  5369. }
  5370. if( pNTEntry->IsAllPlayersGroup() )
  5371. {
  5372. pNTEntry->Unlock();
  5373. DPFERR("Cannot getcontext for the all players group" );
  5374. hResultCode = DPNERR_INVALIDGROUP;
  5375. goto Failure;
  5376. }
  5377. *ppvGroupContext = pNTEntry->GetContext();
  5378. pNTEntry->Unlock();
  5379. pNTEntry->Release();
  5380. pNTEntry = NULL;
  5381. hResultCode = DPN_OK;
  5382. Exit:
  5383. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  5384. return(hResultCode);
  5385. Failure:
  5386. if (pNTEntry)
  5387. {
  5388. pNTEntry->Release();
  5389. pNTEntry = NULL;
  5390. }
  5391. goto Exit;
  5392. }
  5393. #undef DPF_MODNAME
  5394. #define DPF_MODNAME "DN_RegisterLobby"
  5395. STDMETHODIMP DN_RegisterLobby(PVOID pInterface,
  5396. const DPNHANDLE dpnhLobbyConnection,
  5397. IDirectPlay8LobbiedApplication *const pIDP8LobbiedApplication,
  5398. const DWORD dwFlags)
  5399. {
  5400. #ifdef DPNBUILD_NOLOBBY
  5401. DPFX(DPFPREP, 0, "RegisterLobby is not supported!");
  5402. return DPNERR_UNSUPPORTED;
  5403. #else // ! DPNBUILD_NOLOBBY
  5404. DIRECTNETOBJECT *pdnObject;
  5405. #ifndef DPNBUILD_NOPARAMVAL
  5406. HRESULT hResultCode;
  5407. #endif // DPNBUILD_NOPARAMVAL
  5408. DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pIDP8LobbiedApplication [0x%p], dwFlags [0x%lx]",
  5409. pInterface,pIDP8LobbiedApplication,dwFlags);
  5410. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  5411. DNASSERT(pdnObject != NULL);
  5412. #ifndef DPNBUILD_NOPARAMVAL
  5413. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  5414. {
  5415. if( FAILED( hResultCode = DN_ValidateRegisterLobby( pInterface, dpnhLobbyConnection, pIDP8LobbiedApplication, dwFlags ) ) )
  5416. {
  5417. DPFERR( "Error validating register lobby params" );
  5418. DPF_RETURN( hResultCode );
  5419. }
  5420. }
  5421. #endif // !DPNBUILD_NOPARAMVAL
  5422. // Check to ensure message handler registered
  5423. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  5424. {
  5425. DPFERR( "Object is not initialized" );
  5426. DPF_RETURN(DPNERR_UNINITIALIZED);
  5427. }
  5428. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  5429. DNASSERT(pdnObject != NULL);
  5430. if (dwFlags == DPNLOBBY_REGISTER)
  5431. {
  5432. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  5433. if (pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE)
  5434. {
  5435. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5436. return(DPNERR_ALREADYREGISTERED);
  5437. }
  5438. IDirectPlay8LobbiedApplication_AddRef(pIDP8LobbiedApplication);
  5439. pdnObject->pIDP8LobbiedApplication = pIDP8LobbiedApplication;
  5440. pdnObject->dpnhLobbyConnection = dpnhLobbyConnection;
  5441. pdnObject->dwFlags |= DN_OBJECT_FLAG_LOBBY_AWARE;
  5442. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5443. }
  5444. else
  5445. {
  5446. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  5447. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE))
  5448. {
  5449. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5450. return(DPNERR_NOTREGISTERED);
  5451. }
  5452. IDirectPlay8LobbiedApplication_Release(pdnObject->pIDP8LobbiedApplication);
  5453. pdnObject->dpnhLobbyConnection = NULL;
  5454. pdnObject->pIDP8LobbiedApplication = NULL;
  5455. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_LOBBY_AWARE);
  5456. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5457. }
  5458. return(DPN_OK);
  5459. #endif // ! DPNBUILD_NOLOBBY
  5460. }
  5461. #ifndef DPNBUILD_NOLOBBY
  5462. #undef DPF_MODNAME
  5463. #define DPF_MODNAME "DNNotifyLobbyClientOfSettings"
  5464. //
  5465. // DNNotifyLobbyClientOfSettings
  5466. //
  5467. // This function sends a connection settings update to the lobby client informing it that the lobby
  5468. // client settings have changed.
  5469. //
  5470. HRESULT DNNotifyLobbyClientOfSettings(
  5471. DIRECTNETOBJECT * const pdnObject,
  5472. IDirectPlay8LobbiedApplication *pdpLobbiedApp,
  5473. DPNHANDLE dpnConnection,
  5474. IDirectPlay8Address *pHostAddress,
  5475. IDirectPlay8Address *pConnectFromAddress )
  5476. {
  5477. HRESULT hResultCode = DPN_OK;
  5478. DPL_CONNECTION_SETTINGS dplConnectionSettings;
  5479. BOOL fIsHost = FALSE;
  5480. CPackedBuffer packBuffer;
  5481. PBYTE pBuffer = NULL;
  5482. BOOL fINCriticalSection = FALSE;
  5483. CNameTableEntry *pNTEntry = NULL;
  5484. DWORD dwIndex;
  5485. fIsHost = DN_CHECK_LOCALHOST( pdnObject );
  5486. ZeroMemory( &dplConnectionSettings, sizeof( DPL_CONNECTION_SETTINGS ) );
  5487. dplConnectionSettings.dwSize = sizeof( DPL_CONNECTION_SETTINGS );
  5488. dplConnectionSettings.dwFlags = (fIsHost) ? DPLCONNECTSETTINGS_HOST : 0;
  5489. // Lock the object while we make a copy of the app desc.
  5490. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  5491. fINCriticalSection = TRUE;
  5492. // Determine the size of buffer
  5493. packBuffer.Initialize(NULL, 0 );
  5494. hResultCode = pdnObject->ApplicationDesc.Pack(&packBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
  5495. DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  5496. if( hResultCode != DPNERR_BUFFERTOOSMALL )
  5497. {
  5498. DPFX(DPFPREP, 0, "Error getting app desc size hr=0x%x", hResultCode );
  5499. goto NOTIFY_EXIT;
  5500. }
  5501. pBuffer = (BYTE*) DNMalloc(packBuffer.GetSizeRequired());
  5502. if( !pBuffer )
  5503. {
  5504. DPFX(DPFPREP, 0, "Error allocating memory for buffer" );
  5505. hResultCode = DPNERR_OUTOFMEMORY;
  5506. goto NOTIFY_EXIT;
  5507. }
  5508. packBuffer.Initialize(pBuffer,packBuffer.GetSizeRequired());
  5509. hResultCode = pdnObject->ApplicationDesc.Pack(&packBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
  5510. DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
  5511. if( FAILED( hResultCode ) )
  5512. {
  5513. DPFX(DPFPREP, 0, "Error packing app desc hr=0x%x", hResultCode );
  5514. goto NOTIFY_EXIT;
  5515. }
  5516. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5517. fINCriticalSection = FALSE;
  5518. memcpy( &dplConnectionSettings.dpnAppDesc, pBuffer, sizeof( DPN_APPLICATION_DESC ) );
  5519. hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pNTEntry );
  5520. if( FAILED( hResultCode ) )
  5521. {
  5522. DPFX(DPFPREP, 0, "Error getting local player hr=0x%x", hResultCode );
  5523. goto NOTIFY_EXIT;
  5524. }
  5525. // Make sure player name isn't changed while we are working with the entry
  5526. pNTEntry->Lock();
  5527. if( pNTEntry->GetName() )
  5528. {
  5529. dplConnectionSettings.pwszPlayerName = (WCHAR*) DNMalloc((wcslen(pNTEntry->GetName())+1)*sizeof(WCHAR));
  5530. if( !dplConnectionSettings.pwszPlayerName )
  5531. {
  5532. pNTEntry->Unlock();
  5533. DPFX(DPFPREP, 0, "Error allocating memory" );
  5534. goto NOTIFY_EXIT;
  5535. }
  5536. wcscpy( dplConnectionSettings.pwszPlayerName, pNTEntry->GetName() );
  5537. }
  5538. else
  5539. {
  5540. dplConnectionSettings.pwszPlayerName = NULL;
  5541. }
  5542. pNTEntry->Unlock();
  5543. // Release our reference
  5544. pNTEntry->Release();
  5545. // Host address field
  5546. if( fIsHost )
  5547. {
  5548. dplConnectionSettings.pdp8HostAddress = NULL;
  5549. hResultCode = DNGetHostAddressHelper( pdnObject, dplConnectionSettings.ppdp8DeviceAddresses, &dplConnectionSettings.cNumDeviceAddresses );
  5550. if( hResultCode != DPNERR_BUFFERTOOSMALL )
  5551. {
  5552. dplConnectionSettings.cNumDeviceAddresses = 0;
  5553. DPFX(DPFPREP, 0, "Could not get host addresses for lobby update hr=0x%x", hResultCode );
  5554. goto NOTIFY_EXIT;
  5555. }
  5556. dplConnectionSettings.ppdp8DeviceAddresses = (IDirectPlay8Address**) DNMalloc(dplConnectionSettings.cNumDeviceAddresses*sizeof(IDirectPlay8Address*));
  5557. if( !dplConnectionSettings.ppdp8DeviceAddresses )
  5558. {
  5559. DPFX(DPFPREP, 0, "Error allocating memory" );
  5560. dplConnectionSettings.cNumDeviceAddresses = 0;
  5561. hResultCode = DPNERR_OUTOFMEMORY;
  5562. goto NOTIFY_EXIT;
  5563. }
  5564. hResultCode = DNGetHostAddressHelper( pdnObject, dplConnectionSettings.ppdp8DeviceAddresses, &dplConnectionSettings.cNumDeviceAddresses );
  5565. if( FAILED( hResultCode ) )
  5566. {
  5567. dplConnectionSettings.cNumDeviceAddresses = 0;
  5568. DPFX(DPFPREP, 0, "Could not get host addresses for lobby update hr=0x%x", hResultCode );
  5569. goto NOTIFY_EXIT;
  5570. }
  5571. }
  5572. else
  5573. {
  5574. dplConnectionSettings.pdp8HostAddress = pHostAddress;
  5575. dplConnectionSettings.ppdp8DeviceAddresses = &pConnectFromAddress;
  5576. dplConnectionSettings.cNumDeviceAddresses = 1;
  5577. }
  5578. // Update the settings
  5579. hResultCode = IDirectPlay8LobbiedApplication_SetConnectionSettings( pdpLobbiedApp, dpnConnection, &dplConnectionSettings, 0 );
  5580. NOTIFY_EXIT:
  5581. if( dplConnectionSettings.ppdp8DeviceAddresses && fIsHost )
  5582. {
  5583. for( dwIndex = 0; dwIndex < dplConnectionSettings.cNumDeviceAddresses; dwIndex++ )
  5584. {
  5585. IDirectPlay8Address_Release( dplConnectionSettings.ppdp8DeviceAddresses[dwIndex] );
  5586. }
  5587. DNFree(dplConnectionSettings.ppdp8DeviceAddresses);
  5588. }
  5589. if( dplConnectionSettings.pwszPlayerName )
  5590. DNFree(dplConnectionSettings.pwszPlayerName);
  5591. if( fINCriticalSection )
  5592. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5593. if( pBuffer )
  5594. DNFree(pBuffer);
  5595. return hResultCode;
  5596. }
  5597. #undef DPF_MODNAME
  5598. #define DPF_MODNAME "DNUpdateLobbyStatus"
  5599. HRESULT DNUpdateLobbyStatus(DIRECTNETOBJECT *const pdnObject,
  5600. const DWORD dwStatus)
  5601. {
  5602. HRESULT hResultCode;
  5603. IDirectPlay8LobbiedApplication *pIDP8LobbiedApplication;
  5604. DPNHANDLE dpnhLobbyConnection = NULL;
  5605. IDirectPlay8Address *pHostAddress = NULL;
  5606. IDirectPlay8Address *pConnectFromAddress = NULL;
  5607. DPFX(DPFPREP, 4,"Parameters: dwStatus [0x%lx]",dwStatus);
  5608. DNASSERT(pdnObject != NULL);
  5609. pIDP8LobbiedApplication = NULL;
  5610. //
  5611. // Get lobbied application interface, if it exists and other settings we need
  5612. //
  5613. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  5614. if ((pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE) && (pdnObject->pIDP8LobbiedApplication))
  5615. {
  5616. IDirectPlay8LobbiedApplication_AddRef(pdnObject->pIDP8LobbiedApplication);
  5617. pIDP8LobbiedApplication = pdnObject->pIDP8LobbiedApplication;
  5618. dpnhLobbyConnection = pdnObject->dpnhLobbyConnection;
  5619. pConnectFromAddress = pdnObject->pIDP8ADevice;
  5620. pHostAddress = pdnObject->pConnectAddress;
  5621. if( pConnectFromAddress )
  5622. {
  5623. IDirectPlay8Address_AddRef( pConnectFromAddress );
  5624. }
  5625. if( pHostAddress )
  5626. {
  5627. IDirectPlay8Address_AddRef( pHostAddress );
  5628. }
  5629. }
  5630. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5631. //
  5632. // Update status and release object
  5633. //
  5634. if (pIDP8LobbiedApplication)
  5635. {
  5636. // If we are about to do a connection notification
  5637. // we send the updated connection settings.
  5638. //
  5639. // This gives lobby client full picture.
  5640. //
  5641. if( dwStatus == DPLSESSION_CONNECTED )
  5642. {
  5643. DNNotifyLobbyClientOfSettings(pdnObject, pIDP8LobbiedApplication, dpnhLobbyConnection, pHostAddress, pConnectFromAddress );
  5644. }
  5645. IDirectPlay8LobbiedApplication_UpdateStatus(pIDP8LobbiedApplication,dpnhLobbyConnection,dwStatus,0);
  5646. IDirectPlay8LobbiedApplication_Release(pIDP8LobbiedApplication);
  5647. pIDP8LobbiedApplication = NULL;
  5648. if( pHostAddress )
  5649. {
  5650. IDirectPlay8Address_Release( pHostAddress );
  5651. }
  5652. if( pConnectFromAddress )
  5653. {
  5654. IDirectPlay8Address_Release( pConnectFromAddress );
  5655. }
  5656. }
  5657. hResultCode = DPN_OK;
  5658. DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
  5659. return(hResultCode);
  5660. }
  5661. #endif // ! DPNBUILD_NOLOBBY
  5662. #undef DPF_MODNAME
  5663. #define DPF_MODNAME "DN_TerminateSession"
  5664. STDMETHODIMP DN_TerminateSession(PVOID pInterface,
  5665. void *const pvTerminateData,
  5666. const DWORD dwTerminateDataSize,
  5667. const DWORD dwFlags)
  5668. {
  5669. HRESULT hResultCode;
  5670. DIRECTNETOBJECT *pdnObject;
  5671. CRefCountBuffer *pRefCountBuffer;
  5672. CWorkerJob *pWorkerJob;
  5673. DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
  5674. DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pvTerminateData [0x%p], dwTerminateDataSize [%ld], dwFlags [0x%lx]",
  5675. pInterface,pvTerminateData,dwTerminateDataSize,dwFlags);
  5676. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  5677. DNASSERT(pdnObject != NULL);
  5678. #ifndef DPNBUILD_NOPARAMVAL
  5679. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  5680. {
  5681. if( FAILED( hResultCode = DN_ValidateTerminateSession( pInterface, pvTerminateData, dwTerminateDataSize, dwFlags ) ) )
  5682. {
  5683. DPFERR( "Error validating terminatesession params" );
  5684. DPF_RETURN( hResultCode );
  5685. }
  5686. }
  5687. #endif // !DPNBUILD_NOPARAMVAL
  5688. // Check to ensure message handler registered
  5689. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  5690. {
  5691. DPFERR( "Object is not initialized" );
  5692. DPF_RETURN(DPNERR_UNINITIALIZED);
  5693. }
  5694. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  5695. {
  5696. DPFERR("Object is connecting / starting to host" );
  5697. DPF_RETURN(DPNERR_CONNECTING);
  5698. }
  5699. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  5700. {
  5701. DPFERR("You must be connected / hosting to terminate a session" );
  5702. DPF_RETURN(DPNERR_NOCONNECTION);
  5703. }
  5704. pRefCountBuffer = NULL;
  5705. pWorkerJob = NULL;
  5706. if (!DN_CHECK_LOCALHOST(pdnObject))
  5707. {
  5708. DPFERR( "Object is not session host, cannot destroy players" );
  5709. hResultCode = DPNERR_NOTHOST;
  5710. goto Failure;
  5711. }
  5712. //
  5713. // Build terminate message
  5714. //
  5715. hResultCode = RefCountBufferNew(pdnObject,
  5716. sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION) + dwTerminateDataSize,
  5717. MemoryBlockAlloc,
  5718. MemoryBlockFree,
  5719. &pRefCountBuffer);
  5720. if (hResultCode != DPN_OK)
  5721. {
  5722. DPFERR("Could not allocate RefCountBuffer");
  5723. DisplayDNError(0,hResultCode);
  5724. goto Failure;
  5725. }
  5726. pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pRefCountBuffer->GetBufferAddress());
  5727. if (dwTerminateDataSize)
  5728. {
  5729. memcpy(pMsg+1,pvTerminateData,dwTerminateDataSize);
  5730. pMsg->dwTerminateDataOffset = sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION);
  5731. }
  5732. else
  5733. {
  5734. pMsg->dwTerminateDataOffset = 0;
  5735. }
  5736. pMsg->dwTerminateDataSize = dwTerminateDataSize;
  5737. //
  5738. // Worker job to send message to all players
  5739. //
  5740. if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
  5741. {
  5742. DPFERR("Could not allocate new WorkerJob");
  5743. DisplayDNError(0,hResultCode);
  5744. goto Failure;
  5745. }
  5746. pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
  5747. pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_TERMINATE_SESSION );
  5748. pWorkerJob->SetSendNameTableOperationVersion( 0 );
  5749. pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
  5750. pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
  5751. DNQueueWorkerJob(pdnObject,pWorkerJob);
  5752. pWorkerJob = NULL;
  5753. pRefCountBuffer->Release();
  5754. pRefCountBuffer = NULL;
  5755. //
  5756. // Terminate local session
  5757. //
  5758. hResultCode = DNUserTerminateSession(pdnObject,
  5759. DPNERR_HOSTTERMINATEDSESSION,
  5760. pvTerminateData,
  5761. dwTerminateDataSize);
  5762. if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
  5763. {
  5764. DPFERR("Could not create WorkerJob");
  5765. DisplayDNError(0,hResultCode);
  5766. goto Failure;
  5767. }
  5768. pWorkerJob->SetJobType( WORKER_JOB_TERMINATE_SESSION );
  5769. pWorkerJob->SetTerminateSessionReason( DPNERR_HOSTTERMINATEDSESSION );
  5770. DNQueueWorkerJob(pdnObject,pWorkerJob);
  5771. pWorkerJob = NULL;
  5772. hResultCode = DPN_OK;
  5773. Exit:
  5774. DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
  5775. return(hResultCode);
  5776. Failure:
  5777. if (pRefCountBuffer)
  5778. {
  5779. pRefCountBuffer->Release();
  5780. pRefCountBuffer = NULL;
  5781. }
  5782. goto Exit;
  5783. }
  5784. //
  5785. // FUnction that performs work for DN_GetHostAddress and for Lobby informs
  5786. //
  5787. #undef DPF_MODNAME
  5788. #define DPF_MODNAME "DNGetHostAddressHelper"
  5789. HRESULT DNGetHostAddressHelper(DIRECTNETOBJECT *pdnObject,
  5790. IDirectPlay8Address **const prgpAddress,
  5791. DWORD *const pcAddress)
  5792. {
  5793. CAsyncOp *pListenParent;
  5794. CAsyncOp *pListenSP;
  5795. CAsyncOp *pListen;
  5796. CBilink *pBilinkSP;
  5797. CBilink *pBilink;
  5798. DWORD dwListenCount;
  5799. CNameTableEntry *pLocalPlayer;
  5800. IDirectPlay8Address **ppAddress;
  5801. HRESULT hResultCode;
  5802. pListenParent = NULL;
  5803. pListenSP = NULL;
  5804. pListen = NULL;
  5805. pLocalPlayer = NULL;
  5806. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  5807. {
  5808. DPFERR("Could not get local player reference");
  5809. DisplayDNError(0,hResultCode);
  5810. goto Failure;
  5811. }
  5812. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  5813. if ( !(pdnObject->dwFlags & DN_OBJECT_FLAG_LISTENING)
  5814. || !pLocalPlayer->IsHost()
  5815. || (pdnObject->pListenParent == NULL))
  5816. {
  5817. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5818. DPFERR("Not listening or Host player");
  5819. hResultCode = DPNERR_NOTHOST;
  5820. goto Failure;
  5821. }
  5822. pdnObject->pListenParent->AddRef();
  5823. pListenParent = pdnObject->pListenParent;
  5824. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5825. pLocalPlayer->Release();
  5826. pLocalPlayer = NULL;
  5827. //
  5828. // Ensure that the address pointer buffer is large enough
  5829. //
  5830. dwListenCount = 0;
  5831. pListenParent->Lock(); // Prevent changes while we run through
  5832. pBilinkSP = pListenParent->m_bilinkParent.GetNext();
  5833. while (pBilinkSP != &pListenParent->m_bilinkParent)
  5834. {
  5835. pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
  5836. pListenSP->Lock();
  5837. pBilink = pListenSP->m_bilinkParent.GetNext();
  5838. while (pBilink != &pListenSP->m_bilinkParent)
  5839. {
  5840. dwListenCount++;
  5841. pBilink = pBilink->GetNext();
  5842. }
  5843. pListenSP->Unlock();
  5844. pListenSP = NULL;
  5845. pBilinkSP = pBilinkSP->GetNext();
  5846. }
  5847. if (dwListenCount > *pcAddress)
  5848. {
  5849. pListenParent->Unlock();
  5850. *pcAddress = dwListenCount;
  5851. hResultCode = DPNERR_BUFFERTOOSMALL;
  5852. goto Failure;
  5853. }
  5854. //
  5855. // Get addresses of LISTENs
  5856. //
  5857. ppAddress = prgpAddress;
  5858. dwListenCount = 0;
  5859. pBilinkSP = pListenParent->m_bilinkParent.GetNext();
  5860. while (pBilinkSP != &pListenParent->m_bilinkParent)
  5861. {
  5862. pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
  5863. pListenSP->Lock();
  5864. pBilink = pListenSP->m_bilinkParent.GetNext();
  5865. while (pBilink != &pListenSP->m_bilinkParent)
  5866. {
  5867. pListen = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
  5868. if (pListen->GetProtocolHandle() != NULL)
  5869. {
  5870. SPGETADDRESSINFODATA spInfoData;
  5871. memset(&spInfoData,0x00,sizeof(SPGETADDRESSINFODATA));
  5872. spInfoData.Flags = SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES;
  5873. if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData,pListen->GetProtocolHandle(),&spInfoData)) != DPN_OK)
  5874. {
  5875. DPFERR("Could not get LISTEN address!");
  5876. DisplayDNError(0,hResultCode);
  5877. //
  5878. // Release all the addresses we have so far.
  5879. //
  5880. while (dwListenCount > 0)
  5881. {
  5882. dwListenCount--;
  5883. ppAddress--;
  5884. IDirectPlay8Address_Release(*ppAddress);
  5885. *ppAddress = NULL;
  5886. }
  5887. goto Failure;
  5888. }
  5889. *ppAddress++ = spInfoData.pAddress;
  5890. dwListenCount++;
  5891. }
  5892. pBilink = pBilink->GetNext();
  5893. }
  5894. pListenSP->Unlock();
  5895. pListenSP = NULL;
  5896. pBilinkSP = pBilinkSP->GetNext();
  5897. }
  5898. pListenParent->Unlock();
  5899. *pcAddress = dwListenCount;
  5900. hResultCode = DPN_OK;
  5901. pListenParent->Release();
  5902. pListenParent = NULL;
  5903. Exit:
  5904. DPF_RETURN(hResultCode);
  5905. Failure:
  5906. if (pListenParent)
  5907. {
  5908. pListenParent->Release();
  5909. pListenParent = NULL;
  5910. }
  5911. if (pLocalPlayer)
  5912. {
  5913. pLocalPlayer->Release();
  5914. pLocalPlayer = NULL;
  5915. }
  5916. goto Exit;
  5917. }
  5918. //
  5919. // DN_GetHostAddress
  5920. //
  5921. // We will determine the host addresses by examining the LISTENs which are running.
  5922. // We do this because after Host migration, we may not be running the same LISTEN
  5923. // we started with.
  5924. #undef DPF_MODNAME
  5925. #define DPF_MODNAME "DN_GetHostAddress"
  5926. STDMETHODIMP DN_GetHostAddress(PVOID pInterface,
  5927. IDirectPlay8Address **const prgpAddress,
  5928. DWORD *const pcAddress,
  5929. const DWORD dwFlags)
  5930. {
  5931. HRESULT hResultCode;
  5932. DIRECTNETOBJECT *pdnObject;
  5933. DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], prgpAddress [0x%p], pcAddress [0x%p], dwFlags [0x%lx]",
  5934. pInterface,prgpAddress,pcAddress,dwFlags);
  5935. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  5936. DNASSERT(pdnObject != NULL);
  5937. #ifndef DPNBUILD_NOPARAMVAL
  5938. if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
  5939. {
  5940. if( FAILED( hResultCode = DN_ValidateGetHostAddress( pInterface, prgpAddress, pcAddress, dwFlags ) ) )
  5941. {
  5942. DPFERR( "Error validating gethostaddress params" );
  5943. DPF_RETURN( hResultCode );
  5944. }
  5945. }
  5946. #endif // !DPNBUILD_NOPARAMVAL
  5947. // Check to ensure message handler registered
  5948. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  5949. {
  5950. DPFERR( "Object is not initialized" );
  5951. DPF_RETURN(DPNERR_UNINITIALIZED);
  5952. }
  5953. if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
  5954. {
  5955. DPFERR("Object is connecting / starting to host" );
  5956. DPF_RETURN(DPNERR_CONNECTING);
  5957. }
  5958. if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) )
  5959. {
  5960. DPFERR("You must be connected / hosting to get host address" );
  5961. DPF_RETURN(DPNERR_NOCONNECTION);
  5962. }
  5963. pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface));
  5964. DNASSERT(pdnObject != NULL);
  5965. // Actually do the work and get the addresses
  5966. hResultCode = DNGetHostAddressHelper( pdnObject, prgpAddress, pcAddress );
  5967. DPF_RETURN(hResultCode);
  5968. }
  5969. #undef DPF_MODNAME
  5970. #define DPF_MODNAME "DNUpdateListens"
  5971. HRESULT DNUpdateListens(DIRECTNETOBJECT *const pdnObject,
  5972. const DWORD dwFlags)
  5973. {
  5974. HRESULT hResultCode;
  5975. CAsyncOp *pListenParent;
  5976. DPFX(DPFPREP, 6,"Parameters: dwFlags [0x%u]", dwFlags);
  5977. DNASSERT( pdnObject != NULL );
  5978. DNASSERT( dwFlags != 0 );
  5979. DNASSERT( ! ((dwFlags & DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS) && (dwFlags & DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS)) );
  5980. hResultCode = DPNERR_GENERIC;
  5981. pListenParent = NULL;
  5982. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  5983. if (pdnObject->pListenParent)
  5984. {
  5985. pdnObject->pListenParent->AddRef();
  5986. pListenParent = pdnObject->pListenParent;
  5987. }
  5988. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  5989. if (pListenParent)
  5990. {
  5991. CBilink *pBilinkSP;
  5992. CBilink *pBilink;
  5993. CAsyncOp *pListenSP;
  5994. CAsyncOp *pAsyncOp;
  5995. CAsyncOp **ListenList;
  5996. DWORD dwCount;
  5997. DWORD dwActual;
  5998. dwCount = 0;
  5999. dwActual = 0;
  6000. ListenList = NULL;
  6001. pListenParent->Lock();
  6002. pBilinkSP = pListenParent->m_bilinkParent.GetNext();
  6003. while (pBilinkSP != &pListenParent->m_bilinkParent)
  6004. {
  6005. pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
  6006. pListenSP->Lock();
  6007. pBilink = pListenSP->m_bilinkParent.GetNext();
  6008. while (pBilink != &pListenSP->m_bilinkParent)
  6009. {
  6010. dwCount++;
  6011. pBilink = pBilink->GetNext();
  6012. }
  6013. pListenSP->Unlock();
  6014. pBilinkSP = pBilinkSP->GetNext();
  6015. }
  6016. if (dwCount > 0)
  6017. {
  6018. if ((ListenList = static_cast<CAsyncOp**>(DNMalloc(dwCount*sizeof(CAsyncOp*)))) != NULL)
  6019. {
  6020. pBilinkSP = pListenParent->m_bilinkParent.GetNext();
  6021. while (pBilinkSP != &pListenParent->m_bilinkParent)
  6022. {
  6023. pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
  6024. pListenSP->Lock();
  6025. pBilink = pListenSP->m_bilinkParent.GetNext();
  6026. while (pBilink != &pListenSP->m_bilinkParent)
  6027. {
  6028. pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
  6029. pAsyncOp->AddRef();
  6030. ListenList[dwActual] = pAsyncOp;
  6031. dwActual++;
  6032. if (dwActual > dwCount)
  6033. {
  6034. DNASSERT(FALSE);
  6035. break;
  6036. }
  6037. pBilink = pBilink->GetNext();
  6038. }
  6039. pListenSP->Unlock();
  6040. pBilinkSP = pBilinkSP->GetNext();
  6041. }
  6042. }
  6043. }
  6044. pListenParent->Unlock();
  6045. if ((ListenList != NULL) && (dwActual > 0))
  6046. {
  6047. DWORD dw;
  6048. DWORD dwUpdateFlags;
  6049. HRESULT hrRegister;
  6050. dwUpdateFlags = 0;
  6051. hrRegister = DPNERR_DPNSVRNOTAVAILABLE;
  6052. if (dwFlags & DN_UPDATE_LISTEN_FLAG_HOST_MIGRATE)
  6053. {
  6054. dwUpdateFlags |= DN_UPDATELISTEN_HOSTMIGRATE;
  6055. }
  6056. if (dwFlags & DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS)
  6057. {
  6058. dwUpdateFlags |= DN_UPDATELISTEN_ALLOWENUMS;
  6059. }
  6060. if (dwFlags & DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS)
  6061. {
  6062. dwUpdateFlags |= DN_UPDATELISTEN_DISALLOWENUMS;
  6063. }
  6064. for (dw = 0 ; dw < dwActual ; dw++)
  6065. {
  6066. if ((ListenList[dw]->GetResult() == DPN_OK) && (ListenList[dw]->GetProtocolHandle() != 0))
  6067. {
  6068. if (dwUpdateFlags)
  6069. {
  6070. if (DNPUpdateListen(pdnObject->pdnProtocolData,
  6071. ListenList[dw]->GetProtocolHandle(),
  6072. dwUpdateFlags) == DPN_OK)
  6073. {
  6074. hResultCode = DPN_OK;
  6075. }
  6076. }
  6077. #ifndef DPNBUILD_SINGLEPROCESS
  6078. if (dwFlags & DN_UPDATE_LISTEN_FLAG_DPNSVR)
  6079. {
  6080. if (DNRegisterListenWithDPNSVR(pdnObject,ListenList[dw]) == DPN_OK)
  6081. {
  6082. hrRegister = DPN_OK;
  6083. }
  6084. }
  6085. #endif // ! DPNBUILD_SINGLEPROCESS
  6086. }
  6087. ListenList[dw]->Release();
  6088. ListenList[dw] = NULL;
  6089. }
  6090. if ((dwActual != 0) && (dwFlags & DN_UPDATE_LISTEN_FLAG_DPNSVR))
  6091. {
  6092. hResultCode = hrRegister;
  6093. }
  6094. DNFree(ListenList);
  6095. ListenList = NULL;
  6096. }
  6097. pListenParent->Release();
  6098. pListenParent = NULL;
  6099. }
  6100. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  6101. return(hResultCode);
  6102. }
  6103. #ifndef DPNBUILD_SINGLEPROCESS
  6104. #undef DPF_MODNAME
  6105. #define DPF_MODNAME "DNRegisterListenWithDPNSVR"
  6106. HRESULT DNRegisterListenWithDPNSVR(DIRECTNETOBJECT *const pdnObject,
  6107. CAsyncOp *const pListen)
  6108. {
  6109. HRESULT hResultCode;
  6110. SPGETADDRESSINFODATA spInfo;
  6111. CAsyncOp *pListenSP;
  6112. CServiceProvider *pSP;
  6113. DPFX(DPFPREP, 6,"Parameters: pListen [0x%p]",pListen);
  6114. pListenSP = NULL;
  6115. pSP = NULL;
  6116. pListen->Lock();
  6117. if (pListen->GetParent() == NULL)
  6118. {
  6119. pListen->Unlock();
  6120. DPFX(DPFPREP, 7,"No SP parent for listen async op");
  6121. hResultCode = DPNERR_DOESNOTEXIST;
  6122. goto Failure;
  6123. }
  6124. pListen->GetParent()->AddRef();
  6125. pListenSP = pListen->GetParent();
  6126. pListen->Unlock();
  6127. pListenSP->Lock();
  6128. if (pListenSP->GetSP() == NULL)
  6129. {
  6130. pListenSP->Unlock();
  6131. DPFX(DPFPREP, 7,"No SP for listen SP async op");
  6132. hResultCode = DPNERR_DOESNOTEXIST;
  6133. goto Failure;
  6134. }
  6135. pListenSP->GetSP()->AddRef();
  6136. pSP = pListenSP->GetSP();
  6137. pListenSP->Unlock();
  6138. pListenSP->Release();
  6139. pListenSP = NULL;
  6140. //
  6141. // Determine the address we're actually listening on
  6142. //
  6143. memset(&spInfo,0x00,sizeof(SPGETADDRESSINFODATA));
  6144. spInfo.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
  6145. if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData, pListen->GetProtocolHandle(),&spInfo)) == DPN_OK)
  6146. {
  6147. DPN_SP_CAPS dnSPCaps;
  6148. #ifdef DBG
  6149. TCHAR DP8ABuffer[512] = {0};
  6150. DWORD DP8ASize;
  6151. #endif // DBG
  6152. DNASSERT(spInfo.pAddress != NULL);
  6153. #ifdef DBG
  6154. DP8ASize = 512;
  6155. IDirectPlay8Address_GetURL(spInfo.pAddress,DP8ABuffer,&DP8ASize);
  6156. DPFX(DPFPREP, 7,"Listen address [%s]",DP8ABuffer);
  6157. #endif // DBG
  6158. //
  6159. // Determine if the listen's SP supports DPNSVR
  6160. //
  6161. if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) == DPN_OK)
  6162. {
  6163. if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSDPNSRV)
  6164. {
  6165. DWORD dwRetry;
  6166. //
  6167. // We re-try the registration to catch the case where DPNSVR is shutting
  6168. // down while we are trying to register. Unlikely but has to be handled.
  6169. //
  6170. for( dwRetry = 0; dwRetry < DPNSVR_REGISTER_ATTEMPTS ; dwRetry ++ )
  6171. {
  6172. hResultCode = pdnObject->ApplicationDesc.RegisterWithDPNSVR( spInfo.pAddress );
  6173. if (hResultCode == DPN_OK || hResultCode == DPNERR_ALREADYREGISTERED)
  6174. {
  6175. //
  6176. // Flag registering with DPNSVR for cleanup
  6177. //
  6178. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  6179. pdnObject->dwFlags |= DN_OBJECT_FLAG_DPNSVR_REGISTERED;
  6180. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  6181. hResultCode = DPN_OK;
  6182. break;
  6183. }
  6184. else
  6185. {
  6186. if( dwRetry < DPNSVR_REGISTER_ATTEMPTS )
  6187. {
  6188. DPFX(DPFPREP, 0, "Unable to register ourselves with DPNSVR hr=0x%x, retrying", hResultCode );
  6189. Sleep( DPNSVR_REGISTER_SLEEP );
  6190. }
  6191. else
  6192. {
  6193. DPFX(DPFPREP, 0, "Unable to register ourselves with DPNSVR hr=0x%x", hResultCode );
  6194. }
  6195. }
  6196. }
  6197. }
  6198. }
  6199. IDirectPlay8Address_Release(spInfo.pAddress);
  6200. spInfo.pAddress = NULL;
  6201. }
  6202. pSP->Release();
  6203. pSP = NULL;
  6204. Exit:
  6205. DNASSERT( pListenSP == NULL );
  6206. DNASSERT( pSP == NULL );
  6207. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  6208. return(hResultCode);
  6209. Failure:
  6210. if (pListenSP)
  6211. {
  6212. pListenSP->Release();
  6213. pListenSP = NULL;
  6214. }
  6215. if (pSP)
  6216. {
  6217. pSP->Release();
  6218. pSP = NULL;
  6219. }
  6220. goto Exit;
  6221. }
  6222. #endif // ! DPNBUILD_SINGLEPROCESS
  6223. #undef DPF_MODNAME
  6224. #define DPF_MODNAME "DNAddRefLock"
  6225. HRESULT DNAddRefLock(DIRECTNETOBJECT *const pdnObject)
  6226. {
  6227. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  6228. if ((pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) ||
  6229. !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
  6230. {
  6231. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  6232. return(DPNERR_ALREADYCLOSING);
  6233. }
  6234. pdnObject->dwLockCount++;
  6235. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  6236. return(DPN_OK);
  6237. }
  6238. #undef DPF_MODNAME
  6239. #define DPF_MODNAME "DNDecRefLock"
  6240. void DNDecRefLock(DIRECTNETOBJECT *const pdnObject)
  6241. {
  6242. BOOL fSetEvent;
  6243. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  6244. pdnObject->dwLockCount--;
  6245. if ((pdnObject->dwLockCount == 0) && (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING))
  6246. {
  6247. fSetEvent = TRUE;
  6248. }
  6249. else
  6250. {
  6251. fSetEvent = FALSE;
  6252. }
  6253. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  6254. if (fSetEvent)
  6255. {
  6256. DNSetEvent(pdnObject->hLockEvent);
  6257. }
  6258. }
  6259. #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
  6260. #undef DPF_MODNAME
  6261. #define DPF_MODNAME "DNThreadPoolAddRef"
  6262. void DNThreadPoolAddRef(DIRECTNETOBJECT *const pdnObject)
  6263. {
  6264. LONG lRefCount;
  6265. DNASSERT(pdnObject->lThreadPoolRefCount >= 0);
  6266. lRefCount = DNInterlockedIncrement( (LONG*)&pdnObject->lThreadPoolRefCount );
  6267. DPFX(DPFPREP, 9, "Thread pool refcount = %i", lRefCount);
  6268. }
  6269. #undef DPF_MODNAME
  6270. #define DPF_MODNAME "DNThreadPoolRelease"
  6271. void DNThreadPoolRelease(DIRECTNETOBJECT *const pdnObject)
  6272. {
  6273. LONG lRefCount;
  6274. DNASSERT(pdnObject->lThreadPoolRefCount > 0);
  6275. lRefCount = DNInterlockedDecrement( (LONG*)&pdnObject->lThreadPoolRefCount );
  6276. if (lRefCount == 0)
  6277. {
  6278. DPFX(DPFPREP, 9, "Thread pool refcount = 0, setting shut down event");
  6279. DNASSERT( pdnObject->ThreadPoolShutDownEvent );
  6280. pdnObject->ThreadPoolShutDownEvent->Set();
  6281. }
  6282. else
  6283. {
  6284. DPFX(DPFPREP, 9, "Thread pool refcount = %i", lRefCount);
  6285. }
  6286. }
  6287. #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE