|
|
/*==========================================================================
* * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved. * * File: Common.cpp * Content: DNET common interface routines *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 07/21/99 mjn Created * 12/23/99 mjn Hand all NameTable update sends from Host to worker thread * 12/23/99 mjn Fixed use of Host and AllPlayers short cut pointers * 12/28/99 mjn Moved Async Op stuff to Async.h * 12/29/99 mjn Reformed DN_ASYNC_OP to use hParentOp instead of lpvUserContext * 12/29/99 mjn Added Instance GUID generation in DN_Host * 01/05/00 mjn Return DPNERR_NOINTERFACE if CoCreateInstance fails * 01/06/00 mjn Moved NameTable stuff to NameTable.h * 01/07/00 mjn Implemented DNSEND_NOCOPY flag in DN_SendTo * 01/07/00 mjn Moved Misc Functions to DNMisc.h * 01/08/00 mjn Implemented GetApplicationDesc * 01/09/00 mjn Application Description stuff * 01/10/00 mjn Implemented SetApplicationDesc * 01/11/00 mjn Use CPackedBuffers instead of DN_ENUM_BUFFER_INFOs * 01/13/00 mjn Removed DIRECTNETOBJECT from Pack/UnpackApplicationDesc * 01/14/00 mjn Added pvUserContext to Host API call * 01/14/00 mjn Removed pvUserContext from DN_NAMETABLE_ENTRY * 01/15/00 mjn Replaced DN_COUNT_BUFFER with CRefCountBuffer * 01/16/00 mjn Moved User callback stuff to User.h * 01/18/00 mjn Implemented DNGROUP_AUTODESTRUCT * 01/18/00 rmt Added calls into voice layer for Close * 01/19/00 mjn Replaced DN_SYNC_EVENT with CSyncEvent * 01/20/00 mjn Clean up NameTable operation list in DN_Close * 01/23/00 mjn Added DN_DestroyPlayer and DNTerminateSession * 01/28/00 mjn Added DN_ReturnBuffer * 02/01/00 mjn Added DN_GetCaps, DN_SetCaps * 02/01/00 mjn Implement Player/Group context values * 02/09/00 mjn Implemented DNSEND_COMPLETEONPROCESS * 02/15/00 mjn Implement INFO flags in SetInfo and return context in GetInfo * 02/17/00 mjn Implemented GetPlayerContext and GetGroupContext * 02/17/00 mjn Reordered parameters in EnumServiceProviders,EnumHosts,Connect,Host * 02/18/00 mjn Converted DNADDRESS to IDirectPlayAddress8 * 03/17/00 rmt Moved caps funcs to caps.h/caps.cpp * 03/23/00 mjn Set group context through CreateGroup * mjn Set player context through Host and Connect * mjn Implemented RegisterLobby() * 03/24/00 mjn Release SP when EnumHost completes * 03/25/00 rmt Added call into DPNSVR when host begins * 04/04/00 rmt Added flag to disable calls to DPNSVR and flag to disable * parameter validation * 04/05/00 mjn Fixed DestroyClient API call * 04/06/00 mjn Added DN_GetHostAddress() * 04/07/00 mjn Prevent Initialize() API from being called twice * mjn Ensure Host addresses have SP included * mjn Fixed DN_GetHostAddress() to get address * 04/09/00 mjn Convert DN_Host() and DN_Connect() to use CAsyncOp * 04/10/00 mjn Fixed DN_Close() to use flags * 04/11/00 mjn Use CAsyncOp for ENUMs * mjn Moved ProcessEnumQuery and ProcessEnumResponse to EnumHosts.cpp * mjn DNCancelEnum() uses CAsyncOp * 04/12/00 mjn DNTerminateSession() cancels outstanding ENUMs * mjn DN_Close() cancels ENUMs instead of DNTerminateSession * mjn DN_Close() clears DN_OBJECT_FLAG_DISCONNECTING * 04/13/00 rmt More parameter validation * 04/14/00 mjn Default Host SP to Device SP if not specified * mjn Crack LISTENs in DN_Host for DPNSVR * 04/16/00 mjn DNSendMessage uses CAsyncOp * 04/17/00 mjn DNCancelSend() uses CAsyncOp * 04/17/00 mjn Fixed DN_EnumHosts to use Handle parent and SYNC operation * mjn DN_Close tries to cancel SENDs and ENUMs * 04/18/00 mjn CConnection tracks connection status better * mjn Deinitialize HandleTable, and release addresses in DN_Close * mjn Fixed DN_GetApplicationDesc to return correct size * 04/19/00 mjn Changed DN_SendTo to accept a range of DPN_BUFFER_DESCs and a count * mjn Shut down LISTENs earlier in Close sequence * 04/20/00 mjn Convert ReceiveBuffers to CAsyncOp and reclaim at Close * mjn DN_SendTo() may be invoked by IDirectPlay8Client::DN_Send() * 04/23/00 mjn Added parameter to DNPerformChildSend() * mjn Reimplemented SEND_COMPLETEONPROCESS * 04/24/00 mjn Updated Group and Info operations to use CAsyncOp's * 04/25/00 mjn Added DNCancelConnect to DN_CancelAsyncOperation * 04/26/00 mjn Fixed DN_GetSendQueueInfo to use CAsyncOp's * 04/26/00 mjn Removed DN_ASYNC_OP and related functions * 04/27/00 mjn Cause DN_GetPlayerContext()/DN_GetGroupContext() to fail if disconnecting * 04/28/00 mjn Allow a NULL Device Address in DN_Connect() - steal SP from Host Address * mjn Save user connect data to be passed during CONNECT sequence * mjn Prevent infinite loops in group SENDs * 05/01/00 rmt Bug #33403 - Require DPNSESSION_CLIENT_SERVER mode in client/server mode * 05/01/00 mjn Prevent unusable SPs from being enumerated. * 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer() * 05/04/00 mjn Clean up address list in DN_Host() * 05/05/00 mjn Free pvConnectData in DN_Close() * mjn Fixed leak in DN_GetHostAddress() * 05/16/00 mjn Force return code from ASYNC DN_SendTo() to return DPNERR_PENDING * mjn Better locking for User notifications * 05/30/00 mjn Modified logic for group sends to target connected players only * mjn ASSERT if operations cannot be cancelled in DN_Close() * 05/31/00 mjn Added operation specific SYNC flags * 05/31/00 mjn Prevent ALL_PLAYERS group from being enum'd in DN_EnumClientsAndGroups() * mjn Skip invalid Host addresses * 06/05/00 mjn Fixed DN_SendTo to handle some errors gracefully * 06/19/00 mjn DN_Connect and DN_Host enumerate adapters if ALL_ADAPTERS specified * 06/20/00 mjn Fixed DN_GetHostAddress() to extract host address from LISTENs * mjn DOH! Forgot to change a line in DN_Host() so that LISTENs use enum'd adapter rather than ALL_ADAPTER * 06/22/00 mjn Replace CConnection::MakeConnected() with SetStatus() * 06/23/00 mjn Removed dwPriority from DN_SendTo() * 06/24/00 mjn Added parent CONNECT AsyncOp to DN_Connect() * mjn Return DPNERR_UNINITIALIZED from DN_Close() if not initialized (called twice) * 06/25/00 mjn Added DNUpdateLobbyStatus(), update status for CONNECTED,DISCONNECTED * mjn Set DirectNetObject as CONNECTED earlier in DN_Host() * 06/26/00 mjn Replaced DPNADDCLIENTTOGROUP_SYNC DPNADDPLAYERTOGROUP_SYNC * mjn Replaced DPNREMOVECLIENTFROMGROUP_SYNC with DPNREMOVEPLAYERFROMGROUP_SYNC * mjn Fixed for() loop counter problem - nested counters used the same variable - DOH ! * 06/27/00 mjn Allow priorities to be specified to GetSendQueueInfo() API calls * rmt Added abstraction for COM_Co(Un)Initialize * mjn Removed ASSERT player not found in DN_GetPlayerContext() * mjn Added DPNSEND_NONSEQUENTIAL flag to Send/SendTo * mjn Allow mix-n-match of priorities in GetSendQueueInfo() API call * 07/02/00 mjn Modified DN_SendTo() to use DNSendGroupMessage() * 07/06/00 mjn Added missing completions for group sends * mjn Fixed locking problem in CNameTable::MakeLocalPlayer,MakeHostPlayer,MakeAllPlayersGroup * mjn Turned DPNSEND_NONSEQUENTIAL flag back on in DN_SendTo() * mjn Use SP handle instead of interface * 07/07/00 mjn Cleanup pNewHost on DirectNetObject at close * 07/08/00 mjn Fixed CAsyncOp to contain m_bilinkParent * 07/09/00 rmt Bug #38323 - RegisterLobby needs a DPNHANDLE parameter. * 07/11/00 mjn Added NOLOOPBACK capability to group sends * mjn Fixed DN_EnumHosts() to handle multiple adapters * 07/12/00 mjn Copy user data on EnumHosts() * 07/17/00 mjn Removed redundant SyncEvent->Reset() in DN_Initialize * mjn Clear DN_OBJECT_FLAG_HOST_CONNECTED in DN_Close() * mjn Check correct return value of DNSendGroupMessage() in DN_SendTo() * 07/19/00 aarono Bug#39751 add CancelAsyncOperation flag support. * 07/20/00 mjn Cleaned up DN_Connect() * 07/21/00 RichGr IA64: Use %p format specifier for 32/64-bit pointers. * 07/21/00 mjn Cleaned up DN_Close() to release connection object reference * 07/23/00 mjn Moved assertion in DN_CanceAsyncOperation * 07/25/00 mjn Fail DN_EnumHosts() if no valid device adapters exist * 07/26/00 mjn Fix error codes returned from DN_Connect(),DN_GetSendQueueInfo(),DN_DestroyGroup() * DN_AddClientToGroup(),DN_RemoveClientFromGroup(),DN_SetGroupInfo() * DN_GetGroupInfo(),DN_EnumGroupMembers() * mjn Fix DN_GetApplicationDesc() to always return buffer size * 07/26/00 mjn Fixed locking problem with CAsyncOp::MakeChild() * 07/28/00 mjn Revised DN_GetSendQueueInfo() to use queue info on CConnection objects * mjn Cleaned up DN_GetPlayerContext() and DN_GetGroupContext() * 07/29/00 mjn Better clean up of pending Connect()'s during Close() * mjn Check user data size in DN_EnumHosts() * mjn Added fUseCachedCaps to DN_SPEnsureLoaded() * 07/30/00 mjn Replaced DN_NAMETABLE_PENDING_OP with CPendingDeletion * 07/31/00 mjn Added hrReason to DNTerminateSession() * mjn Added dwDestroyReason to DNHostDisconnect() * mjn Cleaned up DN_TerminateSession() * 08/03/00 rmt Bug #41244 - Wrong return codes -- part 2 * 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles. * 08/05/00 mjn Added pParent to DNSendGroupMessage and DNSendMessage() * mjn Ensure cancelled operations don't proceed * mjn Prevent hosting players from calling DN_EnumHosts() * mjn Generate TERMINATE_SESSION notification for host player * 08/06/00 mjn Added CWorkerJob * 08/09/00 mjn Moved no-loop-back test in DN_SendTo() * 08/15/00 rmt Bug #42506 - DPLAY8: LOBBY: Automatic connection settings not being sent * 08/15/00 mjn Remapped DPNERR_INVALIDENDPOINT from DPNERR_INVALIDPLAYER to DPNERR_NOCONNECTION in DN_SendTo() * mjn Addef hProtocol to DNRegisterWithDPNSVR() and removed registration from DN_Host() * 08/16/00 mjn Return DPNERR_INVALIDHOSTADDRESS from DN_EnumHosts() if host address is invalid * 08/20/00 mjn Removed fUseCachedCaps from DN_SPEnsureLoaded() * 08/23/00 mjn Flag DirectNetObject as registered with DPNSVR * 08/24/00 mjn Replace DN_NAMETABLE_OP with CNameTableOp * 08/29/00 mjn Remap DPNERR_INVALIDPLAYER to DPNERR_CONNECTIONLOST in DN_SendTo() * 09/01/00 masonb Modified DN_Close to call CloseHandle on hWorkerThread * 09/04/00 mjn Added CApplicationDesc * 09/05/00 mjn Set NameTable DPNID mask when hosting * 09/06/00 mjn Fixed register with DPNSVR problem * 09/13/00 rmt Bug #44625 - DPVOICE: Multihomed machines are not always enumerable * Moved registration for DPNSVR into ListenComplete * 09/17/00 mjn Split CNameTable.m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups * 10/11/00 mjn Take locks for CNameTableEntry::PackInfo() * 10/12/00 mjn Set async handle completion after succeeding in DN_EnumHosts() * 10/17/00 mjn Fixed clean up for unreachable players * 11/16/00 mjn Fixed uninitialized variable problem in DN_CancelAsyncOperation() * 12/11/00 mjn Allow API calls after TERMINATE_SESSION without calling Close() first * 01/09/01 mjn CancelAsyncOperations() returns DPNERR_CANNOTCANCEL if operation doesn't allow it * 01/10/01 mjn DN_Connect() cancels ENUMs with DPNERR_CONNECTING * 01/22/01 mjn Check closing instead of disconnecting in getting player/group context and info * mjn Fixed debug text * 02/12/01 mjn GetPlayerContext() and GetGroupContext() return DPNERR_NOTREADY if context not yet set * 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's * mjn Use cached enum frame size * 04/11/01 mjn Save hosting flag for query for addressing when listening * 05/02/01 vpo Whistler 380319: "DPLAY8: CORE: Starts listening before creating local nametable entry" * 05/07/01 vpo Whistler 384350: "DPLAY8: CORE: Messages from server can be indicated before connect completes" * 05/14/01 mjn Fix client error handling when completing connect if server not available * 05/22/01 mjn Properly set DirectNetObject as CONNECTED for successful client connect * 06/03/01 mjn Clean up connect parent in DNTerminateSession() * 06/12/01 mjn Ensure DN_Initialize() returns non-DPN_OK value when creating new CSyncEvent or thread fails * 06/25/01 mjn Unregister from DPNSVR in DNTerminateSession() * 07/24/01 mjn Added DPNBUILD_NOPARAMVAL compile flag *@@END_MSINTERNAL * ***************************************************************************/
#include "dncorei.h"
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
HRESULT DNGetHostAddressHelper(DIRECTNETOBJECT *pdnObject, IDirectPlay8Address **const prgpAddress, DWORD *const pcAddress);
//
// Store the user-supplied message handler and context value for call backs
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Initialize"
STDMETHODIMP DN_Initialize(PVOID pInterface, PVOID const pvUserContext, const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags) { HRESULT hResultCode = DPN_OK; DIRECTNETOBJECT *pdnObject; #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
CSyncEvent *pThreadPoolSyncEvent; #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
CSyncEvent *pProtocolSyncEvent; BOOL fApplicationDesc; BOOL fHandleTable; BOOL fProtocol;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pvUserContext [0x%p], pfn [0x%p], dwFlags [0x%lx]", pInterface,pvUserContext,pfn,dwFlags);
#ifndef DPNBUILD_NOPARAMVAL
if( !IsValidDirectPlay8Object( pInterface ) ) { DPFERR("Invalid object specified" ); DPF_RETURN( DPNERR_INVALIDOBJECT ); }
if( pfn == NULL ) { DPFERR("You must specify a callback function" ); DPF_RETURN( DPNERR_INVALIDPARAM ); }
if( dwFlags & ~(DPNINITIALIZE_DISABLEPARAMVAL #ifdef DIRECTPLAYDIRECTX9
| DPNINITIALIZE_HINT_LANSESSION #endif // DIRECTPLAYDIRECTX9
) ) { DPFERR("Invalid flags specified" ); DPF_RETURN( DPNERR_INVALIDFLAGS ); } #endif // !DPNBUILD_NOPARAMVAL
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
// Ensure not already initialized
if (pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) { DPFERR("Initialize has already been called" ); DPF_RETURN(DPNERR_ALREADYINITIALIZED); }
#ifndef DPNBUILD_NOPARAMVAL
// Disable parameter validation flag if DPNINITIALIZE_DISABLEPARAMVAL
// is specified
if( dwFlags & DPNINITIALIZE_DISABLEPARAMVAL ) { pdnObject->dwFlags &= ~(DN_OBJECT_FLAG_PARAMVALIDATION); } #endif // !DPNBUILD_NOPARAMVAL
fApplicationDesc = FALSE; fHandleTable = FALSE; fProtocol = FALSE; pProtocolSyncEvent = NULL; #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
pThreadPoolSyncEvent = NULL; #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
//
// Lock DirectNetObject in case someone's trying something funny
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
//
// Initialize ApplicationDescription
//
if ((hResultCode = pdnObject->ApplicationDesc.Initialize()) != DPN_OK) { DPFERR("Could not initialize ApplicationDesc"); DisplayDNError(0,hResultCode); goto Failure; } fApplicationDesc = TRUE;
//
// Initialize HandleTable
//
if ((hResultCode = pdnObject->HandleTable.Initialize()) != DPN_OK) { DPFERR("Could not initialize HandleTable"); DisplayDNError(0,hResultCode); goto Failure; } fHandleTable = TRUE;
//
// The threadpool interface always exists for the life of the object.
//
DNASSERT(pdnObject->pIDPThreadPoolWork != NULL);
#ifndef DPNBUILD_ONLYONETHREAD
//
// Have the thread pool object try to start at least one thread. Other
// components may request more, but we just need a single worker.
//
// We'll ignore failure, because we could still operate in DoWork mode even
// when starting the thread fails. It most likely failed because the user
// is in that mode already anyway (DPNERR_ALREADYINITIALIZED).
//
hResultCode = IDirectPlay8ThreadPoolWork_RequestTotalThreadCount(pdnObject->pIDPThreadPoolWork, 1, 0); if (hResultCode != DPN_OK) { if (hResultCode != DPNERR_ALREADYINITIALIZED) { DPFX(DPFPREP, 0, "Requesting a single thread failed (err = 0x%lx)!", hResultCode); }
//
// Continue...
//
} #endif // ! DPNBUILD_ONLYONETHREAD
//
// Initialize protocol and create shut-down event
//
DNASSERT(pdnObject->lProtocolRefCount == 0); #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
if ((hResultCode = DNPProtocolInitialize( pdnObject->pdnProtocolData, pdnObject, &g_ProtocolVTBL, pdnObject->pIDPThreadPoolWork, (dwFlags #ifdef DIRECTPLAYDIRECTX9
& DPNINITIALIZE_HINT_LANSESSION #endif // DIRECTPLAYDIRECTX9
))) != DPN_OK) { hResultCode = DPNERR_OUTOFMEMORY; DPFERR("DNPProtocolInitialize() failed"); DisplayDNError(0,hResultCode); goto Failure; } #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
pdnObject->lProtocolRefCount = 1; fProtocol = TRUE;
DNASSERT( pdnObject->hProtocolShutdownEvent == NULL ); if ((hResultCode = SyncEventNew(pdnObject,&pProtocolSyncEvent)) != DPN_OK) { DPFERR("Could not get protocol shutdown event"); DisplayDNError(0,hResultCode); goto Failure; }
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
if ((hResultCode = SyncEventNew(pdnObject,&pThreadPoolSyncEvent)) != DPN_OK) { DPFERR("Could not create threadpool shutdown event"); DisplayDNError(0,hResultCode); goto Failure; } pdnObject->lThreadPoolRefCount = 1;
pdnObject->ThreadPoolShutDownEvent = pThreadPoolSyncEvent; pThreadPoolSyncEvent = NULL; #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
pdnObject->hProtocolShutdownEvent = pProtocolSyncEvent; pProtocolSyncEvent = NULL; pdnObject->pfnDnUserMessageHandler = pfn; pdnObject->pvUserContext = pvUserContext; pdnObject->dwFlags |= DN_OBJECT_FLAG_INITIALIZED; pdnObject->dwMaxFrameSize = 0;
hResultCode = DPN_OK;
Exit: DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (fApplicationDesc) { pdnObject->ApplicationDesc.Deinitialize(); } if (fHandleTable) { pdnObject->HandleTable.Deinitialize(); } if (pProtocolSyncEvent) { pProtocolSyncEvent->ReturnSelfToPool(); pProtocolSyncEvent = NULL; } #ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
if (pThreadPoolSyncEvent) { pThreadPoolSyncEvent->ReturnSelfToPool(); pThreadPoolSyncEvent = NULL; } #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
if (fProtocol) { DNProtocolRelease(pdnObject); } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Close"
STDMETHODIMP DN_Close(PVOID pInterface,const DWORD dwFlags) { HRESULT hResultCode = DPN_OK; DIRECTNETOBJECT *pdnObject; CBilink *pBilink; CAsyncOp *pAsyncOp; CConnection *pConnection; CPendingDeletion *pPending; CServiceProvider *pSP; BOOL fWaitForEvent;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dwFlags [0x%lx]",pInterface,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL); #ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( !IsValidDirectPlay8Object( pInterface ) ) { DPFERR("Invalid object specified " ); DPF_RETURN( DPNERR_INVALIDOBJECT ); }
#ifdef DIRECTPLAYDIRECTX9
if( dwFlags & ~(DPNCLOSE_IMMEDIATE) ) #else
if (dwFlags != 0) #endif
{ DPFERR("Invalid flags"); DPF_RETURN( DPNERR_INVALIDFLAGS ); } } #endif // !DPNBUILD_NOPARAMVAL
pAsyncOp = NULL; pConnection = NULL; pSP = NULL;
//
// Ensure this isn't being called on a callback thread
//
DNEnterCriticalSection(&pdnObject->csCallbackThreads); pBilink = pdnObject->m_bilinkCallbackThreads.GetNext(); while (pBilink != &pdnObject->m_bilinkCallbackThreads) { if ((CONTAINING_CALLBACKTHREAD(pBilink))->IsCurrentThread()) { DNLeaveCriticalSection(&pdnObject->csCallbackThreads); DPFERR("Cannot call Close on a callback thread"); hResultCode = DPNERR_NOTALLOWED; goto Failure; } pBilink = pBilink->GetNext(); } DNLeaveCriticalSection(&pdnObject->csCallbackThreads); //
// Flag as closing. Make sure this hasn't already been called.
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
// Ensure already initialized
if ( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) ) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); DPFX(DPFPREP, 1, "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); } if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); DPFERR("Already closing" ); hResultCode = DPNERR_ALREADYCLOSING; goto Failure; } pdnObject->dwFlags |= DN_OBJECT_FLAG_CLOSING; #ifdef DIRECTPLAYDIRECTX9
if (dwFlags & DPNCLOSE_IMMEDIATE) { //
// We will set DN_OBJECT_FLAG_CLOSING_IMMEDIATE so that any disconnects from now on will be immediate
//
pdnObject->dwFlags |= DN_OBJECT_FLAG_CLOSING_IMMEDIATE; } #endif
if (pdnObject->dwLockCount == 0) { fWaitForEvent = FALSE; } else { fWaitForEvent = TRUE; } pdnObject->dwClosingThreadID = GetCurrentThreadId();
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifdef DBG
{ CNameTableEntry *pLocalPlayer;
if (pdnObject->NameTable.GetLocalPlayerRef(&pLocalPlayer) == DPN_OK) { DPFX(DPFPREP, 0,"Local player was [0x%lx]",pLocalPlayer->GetDPNID()); pLocalPlayer->Release(); } } #endif // DBG
//
// If there are operations underway, we will wait for them to complete and release the lock count
//
if (fWaitForEvent) { hResultCode = IDirectPlay8ThreadPoolWork_WaitWhileWorking(pdnObject->pIDPThreadPoolWork, HANDLE_FROM_DNHANDLE(pdnObject->hLockEvent), 0); DNASSERT(hResultCode == DPN_OK); }
//
// Cancel connect
//
DPFX(DPFPREP, 3,"Checking CONNECT"); DNEnterCriticalSection(&pdnObject->csDirectNetObject); pAsyncOp = pdnObject->pConnectParent; pdnObject->pConnectParent = NULL; pSP = pdnObject->pConnectSP; pdnObject->pConnectSP = NULL; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp) { pAsyncOp->Lock(); pConnection = pAsyncOp->GetConnection(); pAsyncOp->SetConnection( NULL ); pAsyncOp->Unlock();
DPFX(DPFPREP, 3,"Canceling CONNECT"); hResultCode = DNCancelChildren(pdnObject,pAsyncOp); DPFX(DPFPREP, 3,"Canceling CONNECT returned [0x%lx]",hResultCode);
pAsyncOp->Release(); pAsyncOp = NULL;
if (pConnection) { pConnection->Disconnect(); pConnection->Release(); pConnection = NULL; } }
if (pSP) { pSP->Release(); pSP = NULL; }
//
// Remove outstanding ENUMs, SENDs, RECEIVE_BUFFERs
//
DPFX(DPFPREP, 3,"Canceling outstanding operations"); hResultCode = DNCancelActiveCommands(pdnObject,( DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_ENUM_RESPONSE | DN_CANCEL_FLAG_USER_SEND | DN_CANCEL_FLAG_INTERNAL_SEND | DN_CANCEL_FLAG_RECEIVE_BUFFER #ifndef DPNBUILD_NOMULTICAST
| DN_CANCEL_FLAG_JOIN #endif // ! DPNBUILD_NOMULTICAST
), NULL, FALSE, 0); DPFX(DPFPREP, 3,"Canceling outstanding operations returned [0x%lx]",hResultCode);
//
// Cancel any REQUESTs
//
DPFX(DPFPREP, 3,"Canceling requests"); hResultCode = DNCancelRequestCommands(pdnObject); DPFX(DPFPREP, 3,"Canceling requests returned [0x%lx]",hResultCode);
#ifndef DPNBUILD_NOMULTICAST
//
// Disconnect from multicast group
//
DPFX(DPFPREP, 3,"Disconnecting from multicast group"); DNEnterCriticalSection(&pdnObject->csDirectNetObject); pBilink = pdnObject->m_bilinkMulticast.GetNext(); while (pBilink != &pdnObject->m_bilinkMulticast) { pConnection = CONTAINING_OBJECT(pBilink,CConnection,m_bilinkMulticast); pConnection->m_bilinkMulticast.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csDirectNetObject); pConnection->Disconnect(); pConnection->Release(); pConnection = NULL; DNEnterCriticalSection(&pdnObject->csDirectNetObject); pBilink = pdnObject->m_bilinkMulticast.GetNext(); }
if (pdnObject->pMulticastSend) { pConnection = pdnObject->pMulticastSend; pdnObject->pMulticastSend = NULL; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if (pConnection) { pConnection->Disconnect(); pConnection->Release(); pConnection = NULL; } DNASSERT(pConnection == NULL); #endif // DPNBUILD_NOMULTICAST
//
// Terminate session. This will remove all players from the NameTable
//
DPFX(DPFPREP, 3,"Terminate Session"); if ((hResultCode = DNTerminateSession(pdnObject,DPN_OK)) != DPN_OK) { DPFERR("Could not terminate session"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); }
//
// Disconnect any indicated connections
//
DNEnterCriticalSection(&pdnObject->csConnectionList); while (pdnObject->m_bilinkIndicated.GetNext() != &pdnObject->m_bilinkIndicated) { pConnection = CONTAINING_OBJECT(pdnObject->m_bilinkIndicated.GetNext(),CConnection,m_bilinkIndicated); pConnection->m_bilinkIndicated.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csConnectionList);
DNASSERT(pConnection->GetDPNID() == 0);
pConnection->Disconnect(); pConnection->Release(); pConnection = NULL;
DNEnterCriticalSection(&pdnObject->csConnectionList); } DNLeaveCriticalSection(&pdnObject->csConnectionList);
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
//
// Release SP's
//
DPFX(DPFPREP, 3,"Releasing SPs"); DN_SPReleaseAll(pdnObject); #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
//
// Shut down protocol
//
DPFX(DPFPREP, 3,"Shutting down Protocol"); DNProtocolRelease(pdnObject); pdnObject->hProtocolShutdownEvent->WaitForEvent(); #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
if ((hResultCode = DNPProtocolShutdown(pdnObject->pdnProtocolData)) != DPN_OK) { DPFERR("Could not shut down Protocol Layer !"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); } #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
pdnObject->hProtocolShutdownEvent->ReturnSelfToPool(); pdnObject->hProtocolShutdownEvent = NULL;
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
//
// Wait for thread pool to be done
//
DNThreadPoolRelease(pdnObject); pdnObject->ThreadPoolShutDownEvent->WaitForEvent(); pdnObject->ThreadPoolShutDownEvent->ReturnSelfToPool(); pdnObject->ThreadPoolShutDownEvent = NULL; #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
//
// The threadpool interface always exists for the life of the object.
//
DNASSERT(pdnObject->pIDPThreadPoolWork != NULL);
//
// Deinitialize HandleTable
//
DPFX(DPFPREP, 3,"Deinitializing HandleTable"); pdnObject->HandleTable.Deinitialize();
//
// Reset NameTable
//
DPFX(DPFPREP, 3,"Resetting NameTable"); pdnObject->NameTable.ResetNameTable(); //
// Deinitialize ApplicationDescription
//
DPFX(DPFPREP, 3,"Deinitializing ApplicationDesc"); pdnObject->ApplicationDesc.Deinitialize();
//
// Any pending NameTable operations
//
pBilink = pdnObject->m_bilinkPendingDeletions.GetNext(); while (pBilink != &pdnObject->m_bilinkPendingDeletions) { pPending = CONTAINING_OBJECT(pBilink,CPendingDeletion,m_bilinkPendingDeletions); pBilink = pBilink->GetNext(); pPending->m_bilinkPendingDeletions.RemoveFromList(); pPending->ReturnSelfToPool(); pPending = NULL; }
//
// Misc Clean Up
//
if (pdnObject->pIDP8ADevice) { IDirectPlay8Address_Release(pdnObject->pIDP8ADevice); pdnObject->pIDP8ADevice = NULL; } if (pdnObject->pvConnectData) { DNFree(pdnObject->pvConnectData); pdnObject->pvConnectData = NULL; pdnObject->dwConnectDataSize = 0; }
if( pdnObject->pConnectAddress ) { IDirectPlay8Address_Release( pdnObject->pConnectAddress ); pdnObject->pConnectAddress = NULL; }
#ifndef DPNBUILD_NOVOICE
if( pdnObject->pTargetList ) { delete [] pdnObject->pTargetList; pdnObject->pTargetList = NULL; }
if( pdnObject->pExpandedTargetList ) { delete [] pdnObject->pExpandedTargetList; pdnObject->pExpandedTargetList = NULL; } #endif // !DPNBUILD_NOVOICE
#ifndef DPNBUILD_NOLOBBY
pdnObject->dpnhLobbyConnection = NULL;
// Release our hold on the lobbiedapplication
if( pdnObject->pIDP8LobbiedApplication) { IDirectPlay8LobbiedApplication_Release(pdnObject->pIDP8LobbiedApplication); pdnObject->pIDP8LobbiedApplication = NULL; } #endif // ! DPNBUILD_NOLOBBY
//
// Reset DirectNet object flag
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags &= (~( DN_OBJECT_FLAG_INITIALIZED | DN_OBJECT_FLAG_CLOSING // | DN_OBJECT_FLAG_DISCONNECTING
// | DN_OBJECT_FLAG_HOST_CONNECTED
| DN_OBJECT_FLAG_LOCALHOST )); pdnObject->dwMaxFrameSize = 0; pdnObject->dwClosingThreadID = 0; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
Exit: DNASSERT( pAsyncOp == NULL ); DNASSERT( pConnection == NULL ); DNASSERT( pSP == NULL );
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: goto Exit; }
//
// Enumerate SP's if no SPGUID supplied, or SP Adapters if an SPGUID is supplied
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumServiceProviders"
STDMETHODIMP DN_EnumServiceProviders( PVOID pInterface, const GUID *const pguidServiceProvider, const GUID *const pguidApplication, DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer, DWORD *const pcbEnumData, DWORD *const pcReturned, const DWORD dwFlags ) { #if ((defined(DPNBUILD_ONLYONEADAPTER)) || (defined(DPNBUILD_ONLYONESP)))
DPFX(DPFPREP, 0, "Enumerating service providers or their adapters is not supported!"); return DPNERR_UNSUPPORTED; #else // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONESP
HRESULT hResultCode; PDIRECTNETOBJECT pdnObject;
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]", pInterface,pguidServiceProvider,pguidApplication,pSPInfoBuffer,pcbEnumData,pcReturned,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateEnumServiceProviders( pInterface, pguidServiceProvider, pguidApplication, pSPInfoBuffer, pcbEnumData, pcReturned, dwFlags ) ) ) { DPFERR( "Error validating params" ); DPF_RETURN(hResultCode); } } #endif // DPNBUILD_NOPARAMVAL
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) ) { DPFERR( "Object is not initialized" ); DPF_RETURN( DPNERR_UNINITIALIZED ); }
if (pguidServiceProvider == NULL) // Enumerate all service providers
{ #ifdef DPNBUILD_ONLYONESP
DPFX(DPFPREP, 0, "Enumerating service providers not supported!"); hResultCode = DPNERR_UNSUPPORTED; #else // ! DPNBUILD_ONLYONESP
hResultCode = DN_EnumSP( pdnObject, dwFlags, #ifndef DPNBUILD_LIBINTERFACE
pguidApplication, #endif // ! DPNBUILD_LIBINTERFACE
pSPInfoBuffer, pcbEnumData, pcReturned); #endif // ! DPNBUILD_ONLYONESP
} else // Service provider specified - enumerate adaptors
{ #ifdef DPNBUILD_ONLYONEADAPTER
DPFX(DPFPREP, 0, "Enumerating devices not supported!"); hResultCode = DPNERR_UNSUPPORTED; #else // ! DPNBUILD_ONLYONEADAPTER
hResultCode = DN_EnumAdapters( pdnObject, dwFlags, pguidServiceProvider, #ifndef DPNBUILD_LIBINTERFACE
pguidApplication, #endif // ! DPNBUILD_LIBINTERFACE
pSPInfoBuffer, pcbEnumData, pcReturned); #endif // ! DPNBUILD_ONLYONEADAPTER
}
DPFX(DPFPREP, 3,"Set: *pcbEnumData [%ld], *pcReturned [%ld]",*pcbEnumData,*pcReturned);
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode); #endif // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONESP
}
//
// Cancel an outstanding Async Operation. hAsyncHandle is the operation handle returned when
// the operation was initiated.
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_CancelAsyncOperation"
STDMETHODIMP DN_CancelAsyncOperation(PVOID pvInterface, const DPNHANDLE hAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; CNameTableEntry *pNTEntry; CConnection *pConnection; CAsyncOp *pHandleParent; CAsyncOp *pAsyncOp; DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 2,"Parameters: pvInterface [0x%p], hAsyncOp [0x%lx], dwFlags [0x%lx]", pvInterface,hAsyncOp,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pvInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateCancelAsyncOperation( pvInterface, hAsyncOp, dwFlags ) ) ) { DPFERR( "Error validating params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) ) { DPFERR( "Object is not initialized" ); DPF_RETURN( DPNERR_UNINITIALIZED ); }
pNTEntry = NULL; pConnection = NULL; pAsyncOp = NULL; pHandleParent = NULL;
//
// If hAsyncOp is specified and it's not supposed to be a player ID, we will cancel the
// operation it represents. Otherwise, we will rely on the flags to determine which operations
// to cancel.
//
if ((hAsyncOp) && (! (dwFlags & DPNCANCEL_PLAYER_SENDS))) { //
// Cancel single operation
//
pdnObject->HandleTable.Lock(); if ((hResultCode = pdnObject->HandleTable.Find(hAsyncOp,(PVOID*)&pHandleParent)) != DPN_OK) { pdnObject->HandleTable.Unlock(); DPFERR("Invalid USER Handle specified"); hResultCode = DPNERR_INVALIDHANDLE; goto Failure; } else { pHandleParent->AddRef(); pdnObject->HandleTable.Unlock(); } if ( pHandleParent->GetOpType() != ASYNC_OP_USER_HANDLE ) { DPFERR("Invalid USER Handle specified"); hResultCode = DPNERR_INVALIDHANDLE; goto Failure; }
//
// Some operations may be marked as CANNOT_CANCEL. Return DPNERR_CANNOTCANCEL for these
//
if ( pHandleParent->IsCannotCancel() ) { DPFERR("Operation not allowed to be cancelled"); hResultCode = DPNERR_CANNOTCANCEL; goto Failure; }
hResultCode = DNCancelChildren(pdnObject,pHandleParent);
pHandleParent->Release(); pHandleParent = NULL; } else { //
// Cancel many operations based on flags
//
DWORD dwInternalFlags; HRESULT hr;
//
// Re-map flags
//
dwInternalFlags = 0; if (dwFlags & DPNCANCEL_ALL_OPERATIONS) { #ifdef DPNBUILD_NOMULTICAST
dwInternalFlags = ( DN_CANCEL_FLAG_CONNECT | DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND ); #else // ! DPNBUILD_NOMULTICAST
dwInternalFlags = ( DN_CANCEL_FLAG_CONNECT | DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND | DN_CANCEL_FLAG_JOIN ); #endif // ! DPNBUILD_NOMULTICAST
} else if (dwFlags & DPNCANCEL_CONNECT) { dwInternalFlags = DN_CANCEL_FLAG_CONNECT; } else if (dwFlags & DPNCANCEL_ENUM) { dwInternalFlags = DN_CANCEL_FLAG_ENUM_QUERY; } else if (dwFlags & DPNCANCEL_SEND) { dwInternalFlags = DN_CANCEL_FLAG_USER_SEND; } #ifndef DPNBUILD_NOMULTICAST
else if (dwFlags & DPNCANCEL_JOIN) { dwInternalFlags = DN_CANCEL_FLAG_JOIN; } #endif // ! DPNBUILD_NOMULTICAST
#ifdef DIRECTPLAYDIRECTX9
else if (dwFlags & DPNCANCEL_PLAYER_SENDS) { //
// If the DPNCANCEL_PLAYER_SENDS flag is specified, then hAsyncOp is actually
// a player ID (except Client, where it must be 0, and it means the host player).
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT) { if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef(&pNTEntry)) != DPN_OK) { DPFERR("Unable to find host player"); hResultCode = DPNERR_NOCONNECTION; goto Failure; } } else { if ((hResultCode = pdnObject->NameTable.FindEntry((DPNID) hAsyncOp,&pNTEntry)) != DPN_OK) { DPFERR("Unable to find specified player"); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; }
if (pNTEntry->IsGroup()) { DPFERR("Specified ID is not a player"); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } }
if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { hResultCode = DPNERR_CONNECTIONLOST; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Re-map flags.
//
dwInternalFlags = DN_CANCEL_FLAG_USER_SEND; if (dwFlags & (DPNCANCEL_PLAYER_SENDS_PRIORITY_HIGH | DPNCANCEL_PLAYER_SENDS_PRIORITY_NORMAL | DPNCANCEL_PLAYER_SENDS_PRIORITY_LOW)) { if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_HIGH)) { dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTHIGHPRI; } if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_NORMAL)) { dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTNORMALPRI; } if (! (dwFlags & DPNCANCEL_PLAYER_SENDS_PRIORITY_LOW)) { dwInternalFlags |= DN_CANCEL_FLAG_USER_SEND_NOTLOWPRI; } //
// We should have set at least one of the negation flags.
//
DNASSERT(dwInternalFlags & (DN_CANCEL_FLAG_USER_SEND_NOTHIGHPRI | DN_CANCEL_FLAG_USER_SEND_NOTNORMALPRI | DN_CANCEL_FLAG_USER_SEND_NOTLOWPRI)); } } #endif
else { DNASSERT(FALSE); // Should never get here
} DPFX(DPFPREP, 3,"Re-mapped internal flags [0x%lx]",dwInternalFlags);
//
// Pre-set error code
hResultCode = DPN_OK;
//
// To cancel a CONNECT, look at the DirectNetObject
//
if (dwInternalFlags & DN_CANCEL_FLAG_CONNECT) { DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pConnectParent) { if (pdnObject->pConnectParent->IsChild()) { DNASSERT(pdnObject->pConnectParent->GetParent() != NULL); pdnObject->pConnectParent->GetParent()->AddRef(); pAsyncOp = pdnObject->pConnectParent->GetParent(); } else { pdnObject->pConnectParent->AddRef(); pAsyncOp = pdnObject->pConnectParent; } } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp) { DPFX(DPFPREP, 3,"Canceling CONNECT"); hr = DNCancelChildren(pdnObject,pAsyncOp); if (hr != DPN_OK) { hResultCode = DPNERR_CANNOTCANCEL; DPFX(DPFPREP, 7,"Remapping: [0x%lx] returned by DNCancelChildren to: [0x%lx]",hr, hResultCode); } pAsyncOp->Release(); pAsyncOp = NULL; } }
//
// To cancel ENUMs and SENDs, cancel out of the active list
//
if (dwInternalFlags & (DN_CANCEL_FLAG_ENUM_QUERY | DN_CANCEL_FLAG_USER_SEND)) { DPFX(DPFPREP, 3,"Canceling ENUMs or SENDs"); hr = DNCancelActiveCommands(pdnObject,dwInternalFlags,pConnection,FALSE,0); if (hr != DPN_OK) { hResultCode = DPNERR_CANNOTCANCEL; DPFX(DPFPREP, 7,"Remapping: [0x%lx] returned by DNCancelActiveCommands to: [0x%lx]",hr, hResultCode); } } }
Exit: if (pConnection) { pConnection->Release(); pConnection = NULL; } DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pAsyncOp) { pAsyncOp->Release(); pAsyncOp = NULL; } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Connect"
STDMETHODIMP DN_Connect( PVOID pInterface, const DPN_APPLICATION_DESC *const pdnAppDesc, IDirectPlay8Address *const pHostAddr, IDirectPlay8Address *const pDeviceInfo, const DPN_SECURITY_DESC *const pdnSecurity, const DPN_SECURITY_CREDENTIALS *const pdnCredentials, const void *const pvUserConnectData, const DWORD dwUserConnectDataSize, void *const pvPlayerContext, void *const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) { CAsyncOp *pHandleParent; CAsyncOp *pConnectParent; CAsyncOp *pAsyncOp; HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; CSyncEvent *pSyncEvent; HRESULT volatile hrOperation; IDirectPlay8Address *pIHost; IDirectPlay8Address *pIDevice; IDirectPlay8Address *pIAdapter; DWORD dwConnectFlags; #ifndef DPNBUILD_ONLYONESP
GUID guidSP; #endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
GUID guidAdapter; #endif // ! DPNBUILD_ONLYONEADAPTER
void *pvConnectData; void *pvAdapterBuffer; DPN_SP_CAPS dnSPCaps; #ifndef DPNBUILD_ONLYONEADAPTER
BOOL fEnumAdapters; #endif // ! DPNBUILD_ONLYONEADAPTER
CRefCountBuffer *pReply; CServiceProvider *pSP; DWORD dwMultiplexFlag;
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]", pInterface,pdnAppDesc,pHostAddr,pDeviceInfo,pdnSecurity,pdnCredentials,pvUserConnectData,dwUserConnectDataSize,pvPlayerContext,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateConnect( pInterface, pdnAppDesc, pHostAddr, pDeviceInfo, pdnSecurity, pdnCredentials, pvUserConnectData, dwUserConnectDataSize,pvPlayerContext, pvAsyncContext,phAsyncHandle,dwFlags ) ) ) { DPFERR( "Error validating connect params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
// Check to ensure not already connected/connecting
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING) { DPFERR( "Object is already connecting" ); DPF_RETURN(DPNERR_CONNECTING); } if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) { DPFERR( "Object is already connected" ); DPF_RETURN(DPNERR_ALREADYCONNECTED); } if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) { DPFERR( "Object is closing or disconnecting" ); DPF_RETURN(DPNERR_ALREADYCLOSING); }
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTING; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
// Preset these so that they are properly cleaned up
pIHost = NULL; pIDevice = NULL; pIAdapter = NULL; pSyncEvent = NULL; pHandleParent = NULL; pConnectParent = NULL; pAsyncOp = NULL; pvConnectData = NULL; pvAdapterBuffer = NULL; hrOperation = DPNERR_GENERIC; pReply = NULL; pSP = NULL; dwMultiplexFlag = 0;
if ((hResultCode = IDirectPlay8Address_Duplicate(pHostAddr,&pIHost)) != DPN_OK) { DPFERR("Could not duplicate host address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
//
// Duplicate specified Device Address, or create a blank one if NULL
//
if (pDeviceInfo != NULL) { if ((hResultCode = IDirectPlay8Address_Duplicate(pDeviceInfo,&pIDevice)) != DPN_OK) { DPFERR("Could not duplicate device info"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } } else { #ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address, reinterpret_cast<void**>(&pIDevice)); #else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>(&pIDevice), FALSE); #endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK) { DPFERR("Could not create Device Address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } }
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_LIBINTERFACE)))
DNASSERT(pdnObject->pOnlySP != NULL); pdnObject->pOnlySP->AddRef(); pSP = pdnObject->pOnlySP; #else // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
#ifndef DPNBUILD_ONLYONESP
//
// If there is no SP on the device address, then steal it from the Host address
//
if ((hResultCode = IDirectPlay8Address_GetSP(pIDevice,&guidSP)) != DPN_OK) { if ((hResultCode = IDirectPlay8Address_GetSP(pIHost,&guidSP)) != DPN_OK) { DPFERR("Could not retrieve SP from Host Address"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = IDirectPlay8Address_SetSP(pIDevice,&guidSP)) != DPN_OK) { DPFERR("Could not set SP on Device Address"); DisplayDNError(0,hResultCode); goto Failure; } } #endif // ! DPNBUILD_ONLYONESP
//
// Ensure SP is loaded
//
hResultCode = DN_SPEnsureLoaded(pdnObject, #ifndef DPNBUILD_ONLYONESP
&guidSP, #endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_LIBINTERFACE
NULL, #endif // ! DPNBUILD_LIBINTERFACE
&pSP); if (hResultCode != DPN_OK) { DPFERR("Could not find or load SP"); DisplayDNError(0,hResultCode); goto Failure; } #endif // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
//
// Get SP caps
//
if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) != DPN_OK) { DPFERR("Could not get SP caps"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Update DirectNet Application Description
//
pdnObject->ApplicationDesc.Lock(); hResultCode = pdnObject->ApplicationDesc.Update(pdnAppDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD| DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA|DN_APPDESCINFO_FLAG_GUIDS); pdnObject->ApplicationDesc.Unlock();
// Connect flags to Protocol
dwConnectFlags = 0; #ifndef DPNBUILD_NOSPUI
if (dwFlags & DPNCONNECT_OKTOQUERYFORADDRESSING) { dwConnectFlags |= DN_CONNECTFLAGS_OKTOQUERYFORADDRESSING; } #endif // ! DPNBUILD_NOSPUI
if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0) { dwConnectFlags |= DN_CONNECTFLAGS_SESSIONDATA; }
//
// Create parent async op, which will be released when the ENTIRE connection is finished
// including nametable transfer and installation on the local machine
//
if ((hResultCode = AsyncOpNew(pdnObject,&pConnectParent)) != DPN_OK) { DPFERR("Could not create AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pConnectParent->SetOpType( ASYNC_OP_CONNECT ); pConnectParent->MakeParent(); pConnectParent->SetContext( pvPlayerContext ); pConnectParent->SetResult( DPNERR_NOCONNECTION ); pConnectParent->SetCompletion( DNCompleteConnectOperation ); pConnectParent->SetReserved(1);
if (dwFlags & DPNCONNECT_SYNC) { DPFX(DPFPREP, 5,"Sync operation - create sync event"); if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK) { DPFERR("Could not create synchronization event"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pConnectParent->SetSyncEvent( pSyncEvent ); pConnectParent->SetResultPointer( &hrOperation ); pConnectParent->SetOpData( &pReply ); } else { DPFX(DPFPREP, 5,"Async operation - create handle parent"); if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create handle parent"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pHandleParent->SetContext( pvAsyncContext );
pHandleParent->Lock(); if (pHandleParent->IsCancelled()) { pHandleParent->Unlock(); pConnectParent->SetResult( DPNERR_USERCANCEL ); hResultCode = DPNERR_USERCANCEL; goto Failure; } pConnectParent->MakeChild( pHandleParent ); pHandleParent->Unlock(); }
//
// We will need a parent op for the CONNECTs to help with clean up when the initial CONNECT stage is done
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK) { DPFERR("Could not create CONNECT parent"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pAsyncOp->SetOpType( ASYNC_OP_CONNECT ); pAsyncOp->MakeParent(); pAsyncOp->SetResult( DPNERR_NOCONNECTION ); pAsyncOp->SetCompletion( DNCompleteConnectToHost ); pAsyncOp->SetOpFlags( dwConnectFlags );
pConnectParent->Lock(); if (pConnectParent->IsCancelled()) { pConnectParent->Unlock(); pAsyncOp->SetResult( DPNERR_USERCANCEL ); hResultCode = DPNERR_USERCANCEL; goto Failure; } pAsyncOp->MakeChild( pConnectParent ); pConnectParent->Unlock();
//
// Save CONNECT data (if supplied)
//
if (pvUserConnectData && dwUserConnectDataSize) { if ((pvConnectData = DNMalloc(dwUserConnectDataSize)) == NULL) { DPFERR("Could not allocate CONNECT data buffer"); DNASSERT(FALSE); hResultCode = DPNERR_OUTOFMEMORY; goto Failure; } memcpy(pvConnectData,pvUserConnectData,dwUserConnectDataSize); }
//
// Update DirectNet object with relevant data
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pConnectParent->AddRef(); pdnObject->pConnectParent = pConnectParent; if (pvConnectData) { if (pdnObject->pvConnectData) { DNFree(pdnObject->pvConnectData); pdnObject->pvConnectData = NULL; } pdnObject->pvConnectData = pvConnectData; pdnObject->dwConnectDataSize = dwUserConnectDataSize; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifndef DPNBUILD_ONLYONEADAPTER
//
// If there is no adapter specified in the device address,
// we will attempt to CONNECT on each individual adapter if the SP supports it
//
fEnumAdapters = FALSE; if ((hResultCode = IDirectPlay8Address_GetDevice( pIDevice, &guidAdapter )) != DPN_OK) { DPFX(DPFPREP,1,"Could not determine adapter"); DisplayDNError(1,hResultCode);
if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSALLADAPTERS) { DPFX(DPFPREP, 3,"SP supports CONNECTing on all adapters"); fEnumAdapters = TRUE; } } else { DPFX(DPFPREP, 7, "Device address contained adapter GUID."); }
if(fEnumAdapters) { DWORD dwNumAdapters; GUID *pAdapterList = NULL; DN_CONNECT_OP_DATA *pConnectOpData = NULL;
if ((hResultCode = DNEnumAdapterGuids( pdnObject, #ifndef DPNBUILD_ONLYONESP
&guidSP, #endif // ! DPNBUILD_ONLYONESP
0, &pAdapterList, &dwNumAdapters)) != DPN_OK) { DPFERR("Could not enum adapters for this SP"); DisplayDNError(0,hResultCode); goto Failure; } if (dwNumAdapters == 0) { DPFERR("No valid device adapters could be found"); hResultCode = DPNERR_INVALIDDEVICEADDRESS; goto Failure; }
pConnectOpData = pAsyncOp->GetLocalConnectOpData(); pConnectOpData->dwNumAdapters = dwNumAdapters; pConnectOpData->dwCurrentAdapter = 0;
if (dwNumAdapters > 1) { dwMultiplexFlag |= DN_CONNECTFLAGS_ADDITIONALMULTIPLEXADAPTERS; }
//
// Choose first adapter for initial LISTEN call
//
if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice,pAdapterList)) != DPN_OK) { DPFERR("Could not set device adapter"); DisplayDNError(0,hResultCode); MemoryBlockFree(pdnObject,pAdapterList); pAdapterList = NULL; goto Failure; } pConnectOpData->dwCurrentAdapter++; pAsyncOp->SetOpData( pAdapterList ); pAdapterList = NULL; pConnectOpData = NULL; } #endif // ! DPNBUILD_ONLYONEADAPTER
pAsyncOp->SetSP( pSP ); // Set this for DNPerformNextConnect()
//
// Save SP for future connects
//
pSP->AddRef(); DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pConnectSP) { pdnObject->pConnectSP->Release(); pdnObject->pConnectSP = NULL; } pdnObject->pConnectSP = pSP; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->pConnectAddress = pIHost; IDirectPlay8Address_AddRef(pdnObject->pConnectAddress);
//
// CONNECT !
//
hResultCode = DNPerformConnect( pdnObject, NULL, pIDevice, pIHost, pSP, pAsyncOp->GetOpFlags() | dwMultiplexFlag, pAsyncOp); if (hResultCode != DPN_OK) { DPFERR("Could not connect"); DisplayDNError(0,hResultCode); goto Failure; }
pAsyncOp->Release(); pAsyncOp = NULL; pConnectParent->Release(); pConnectParent = NULL;
IDirectPlay8Address_Release(pIHost); pIHost = NULL; IDirectPlay8Address_Release(pIDevice); pIDevice = NULL;
pSP->Release(); pSP = NULL;
if (dwFlags & DPNCONNECT_SYNC) { CNameTableEntry *pHostPlayer;
pHostPlayer = NULL;
if ((hResultCode = pSyncEvent->WaitForEvent()) != DPN_OK) { DPFERR("DNSyncEventWait() terminated bizarrely"); DNASSERT(FALSE); } else { hResultCode = hrOperation; } pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL;
//
// No longer connecting
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING); DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Clients need to release all sends from the server that were
// queued once the CONNECT_COMPLETE gets indicated.
// We prepare to do that now.
//
if ((hrOperation == DPN_OK) && (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT)) { if (pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer ) == DPN_OK) { pHostPlayer->Lock(); pHostPlayer->MakeAvailable(); pHostPlayer->NotifyAddRef(); pHostPlayer->SetInUse(); pHostPlayer->Unlock();
//
// We are now connected
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); } else { //
// If we couldn't get a reference on the server (host player),
// then either the server has disconnected, or we are being shut down.
// In either case, we should return an error
//
DPFX(DPFPREP, 0, "Couldn't get host player reference, failing CONNECT!"); hrOperation = DPNERR_NOCONNECTION; hResultCode = hrOperation; if (pReply) { pReply->Release(); pReply = NULL; } } } else { //
// Connect failed, or this is a peer/server interface
//
}
//
// Generate connect completion
//
DNUserConnectComplete(pdnObject,0,NULL,hrOperation,pReply); if (pReply) { pReply->Release(); pReply = NULL; }
//
// Cancel ENUMs if the CONNECT succeeded and unload SP's
//
if (hrOperation == DPN_OK) { DNCancelActiveCommands(pdnObject,DN_CANCEL_FLAG_ENUM_QUERY,NULL,TRUE,DPNERR_CONNECTING);
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
DN_SPReleaseAll(pdnObject); #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
//
// Actually release queued messages if necessary
//
if (pHostPlayer != NULL) { pHostPlayer->PerformQueuedOperations();
pHostPlayer->Release(); pHostPlayer = NULL; } }
DNASSERT( pHostPlayer == NULL ); } else { pHandleParent->SetCompletion( DNCompleteUserConnect ); if (phAsyncHandle) { *phAsyncHandle = pHandleParent->GetHandle(); } pHandleParent->Release(); pHandleParent = NULL;
hResultCode = DPNERR_PENDING; }
Exit: DNASSERT( pSP == NULL );
DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT);
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pSP) { pSP->Release(); pSP = NULL; } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pConnectParent) { if (SUCCEEDED(pdnObject->HandleTable.Destroy( pConnectParent->GetHandle(), NULL ))) { // Release the HandleTable reference
pConnectParent->Release(); } pConnectParent->Release(); pConnectParent = NULL; } if (pAsyncOp) { pAsyncOp->Release(); pAsyncOp = NULL; } if (pIHost) { IDirectPlay8Address_Release(pIHost); pIHost = NULL; } if (pIDevice) { IDirectPlay8Address_Release(pIDevice); pIDevice = NULL; } if (pIAdapter) { IDirectPlay8Address_Release(pIAdapter); pIAdapter = NULL; } if (pSyncEvent) { pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL; } if (pvAdapterBuffer) { DNFree(pvAdapterBuffer); pvAdapterBuffer = NULL; } DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pIDP8ADevice) { IDirectPlay8Address_Release(pdnObject->pIDP8ADevice); pdnObject->pIDP8ADevice = NULL; } if (pdnObject->pvConnectData) { DNFree(pdnObject->pvConnectData); pdnObject->pvConnectData = NULL; pdnObject->dwConnectDataSize = 0; } if( pdnObject->pConnectAddress ) { IDirectPlay8Address_Release( pdnObject->pConnectAddress ); pdnObject->pConnectAddress = NULL; } if (pdnObject->pConnectSP) { pdnObject->pConnectSP->Release(); pdnObject->pConnectSP = NULL; } pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING); DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
goto Exit; }
// DN_GetSendQueueInfo
//
// Get info about the user send queue.
// This will find the CConnection for a given player and extract the required queue infor from it.
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetSendQueueInfo"
STDMETHODIMP DN_GetSendQueueInfo(PVOID pInterface, const DPNID dpnid, DWORD *const pdwNumMsgs, DWORD *const pdwNumBytes, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; DWORD dwQueueFlags; DWORD dwNumMsgs; DWORD dwNumBytes; CNameTableEntry *pNTEntry; CConnection *pConnection; HRESULT hResultCode;
DNASSERT(pInterface != NULL);
DPFX(DPFPREP, 2,"Parameters : pInterface [0x%p], dpnid [0x%lx], pdwNumMsgs [0x%p], pdwNumBytes [0x%p], dwFlags [0x%lx]", pInterface,dpnid,pdwNumMsgs,pdwNumBytes,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { HRESULT hrResult; if( FAILED( hrResult = DN_ValidateGetSendQueueInfo( pInterface, pdwNumMsgs, pdwNumBytes, dwFlags ) ) ) { DPFERR( "Error validating params" ); DPF_RETURN( hrResult ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR( "Object is already connecting" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED ) ) { DPFERR("Object is not connected" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pNTEntry = NULL; pConnection = NULL;
//
// Validate specified player ID and get CConnection
//
if((hResultCode = pdnObject->NameTable.FindEntry( dpnid, &pNTEntry )) != DPN_OK) { DPFX(DPFPREP, 0,"Could not find Player ID [0x%lx] in NameTable", dpnid ); if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find entry in deleted list either"); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } pNTEntry->Release(); pNTEntry = NULL; hResultCode = DPNERR_CONNECTIONLOST; goto Failure; } if (pNTEntry->IsLocal() || pNTEntry->IsGroup()) { hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { hResultCode = DPNERR_CONNECTIONLOST; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Determine required queues
//
dwQueueFlags = dwFlags & (DPNGETSENDQUEUEINFO_PRIORITY_HIGH | DPNGETSENDQUEUEINFO_PRIORITY_NORMAL | DPNGETSENDQUEUEINFO_PRIORITY_LOW); if (dwQueueFlags == 0) { dwQueueFlags = (DPNGETSENDQUEUEINFO_PRIORITY_HIGH | DPNGETSENDQUEUEINFO_PRIORITY_NORMAL | DPNGETSENDQUEUEINFO_PRIORITY_LOW); }
//
// Extract required info
//
dwNumMsgs = 0; dwNumBytes = 0; pConnection->Lock(); if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_HIGH) { dwNumMsgs += pConnection->GetHighQueueNum(); dwNumBytes += pConnection->GetHighQueueBytes(); } if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_NORMAL) { dwNumMsgs += pConnection->GetNormalQueueNum(); dwNumBytes += pConnection->GetNormalQueueBytes(); } if (dwQueueFlags & DPNGETSENDQUEUEINFO_PRIORITY_LOW) { dwNumMsgs += pConnection->GetLowQueueNum(); dwNumBytes += pConnection->GetLowQueueBytes(); } pConnection->Unlock(); pConnection->Release(); pConnection = NULL;
if (pdwNumMsgs) { *pdwNumMsgs = dwNumMsgs; DPFX(DPFPREP, 3,"Setting: *pdwNumMsgs [%ld]",dwNumMsgs); } if (pdwNumBytes) { *pdwNumBytes = dwNumBytes; DPFX(DPFPREP, 3,"Setting: *pdwNumBytes [%ld]",dwNumBytes); }
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetApplicationDesc"
STDMETHODIMP DN_GetApplicationDesc(PVOID pInterface, DPN_APPLICATION_DESC *const pAppDescBuffer, DWORD *const pcbDataSize, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; CPackedBuffer packedBuffer;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pAppDescBuffer [0x%p], pcbDataSize [0x%p], dwFlags [0x%lx]", pInterface,pAppDescBuffer,pcbDataSize,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateGetApplicationDesc( pInterface, pAppDescBuffer, pcbDataSize, dwFlags ) ) ) { DPFERR( "Failed validation getappdesc" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("Object is not connected or hosting" ); DPF_RETURN(DPNERR_NOCONNECTION); }
//
// Initialize PackedBuffer
//
packedBuffer.Initialize(static_cast<void*>(pAppDescBuffer),*pcbDataSize);
//
// Try to pack in the application description.
// If it won't fit, the required size will be in the PackedBuffer.
//
hResultCode = pdnObject->ApplicationDesc.Pack(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD| DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
//
// Ensure we know what's going on
//
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_BUFFERTOOSMALL)) { DPFERR("Unknown error occurred packing application description"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_GENERIC; goto Failure; }
//
// Size of buffer
//
*pcbDataSize = packedBuffer.GetSizeRequired();
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_SetApplicationDesc"
STDMETHODIMP DN_SetApplicationDesc(PVOID pInterface, const DPN_APPLICATION_DESC *const pdnApplicationDesc, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode = DPN_OK; CRefCountBuffer *pRefCountBuffer; CPackedBuffer packedBuffer; CWorkerJob *pWorkerJob; DWORD dwAppDescInfoSize; DWORD dwEnumFrameSize; DWORD dwUpdateFlags; CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnApplicationDesc [0x%p], dwFlags [0x%lx]", pInterface,pdnApplicationDesc,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateSetApplicationDesc( pInterface, pdnApplicationDesc, dwFlags ) ) ) { DPFERR( "Error validating setappdesc params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR( "Object has not yet completed connecting / hosting" ); DPF_RETURN(DPNERR_CONNECTING); }
if ( !DN_CHECK_LOCALHOST( pdnObject ) ) { DPFERR("Object is not connected or hosting" ); DPF_RETURN(DPNERR_NOTHOST); }
pNTEntry = NULL; pRefCountBuffer = NULL; pWorkerJob = NULL;
//
// This can only be called by the host
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pNTEntry )) != DPN_OK) { DPFERR("Could not get local player"); hResultCode = DPNERR_NOTHOST; goto Failure; } if (!pNTEntry->IsHost()) { DPFERR("Not Host player"); hResultCode = DPNERR_NOTHOST; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Use cached max enum frame size
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); dwEnumFrameSize = pdnObject->dwMaxFrameSize; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); DNASSERT( dwEnumFrameSize >= (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)) ); if (dwEnumFrameSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO) + pdnApplicationDesc->dwApplicationReservedDataSize)) { DPFERR("Not enough room for the application reserved data"); hResultCode = DPNERR_DATATOOLARGE; goto Failure; }
//
// Update Host player's application desc first
//
pdnObject->ApplicationDesc.Lock(); if (pdnApplicationDesc->dwMaxPlayers > 0) { if (pdnApplicationDesc->dwMaxPlayers < pdnObject->ApplicationDesc.GetCurrentPlayers()) { DPFERR("Cannot set max players to less than the current number of players"); pdnObject->ApplicationDesc.Unlock(); hResultCode = DPNERR_SESSIONFULL; goto Failure; } } hResultCode = pdnObject->ApplicationDesc.Update(pdnApplicationDesc,DN_APPDESCINFO_FLAG_SESSIONNAME| DN_APPDESCINFO_FLAG_PASSWORD|DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA); pdnObject->ApplicationDesc.Unlock(); if (hResultCode != DPN_OK) { DPFERR("Could not update Application Desciption"); DisplayDNError(0,hResultCode); goto Failure; }
#ifdef DIRECTPLAYDIRECTX9
//
// Update Listen if enums allowed/disallowed
//
dwUpdateFlags = 0; DNEnterCriticalSection(&pdnObject->csDirectNetObject); if ((pdnObject->dwFlags & DN_OBJECT_FLAG_DISALLOW_ENUMS) && !(pdnApplicationDesc->dwFlags & DPNSESSION_NOENUMS)) { dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS; pdnObject->dwFlags &= ~DN_OBJECT_FLAG_DISALLOW_ENUMS; } else if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_DISALLOW_ENUMS) && (pdnApplicationDesc->dwFlags & DPNSESSION_NOENUMS)) { dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS; pdnObject->dwFlags |= DN_OBJECT_FLAG_DISALLOW_ENUMS; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if (dwUpdateFlags) { DNUpdateListens(pdnObject,dwUpdateFlags); } #endif // DIRECTPLAYDIRECTX9
//
// Inform host application
//
hResultCode = DNUserUpdateAppDesc(pdnObject);
//
// Get Application Description Info size
//
packedBuffer.Initialize(NULL,0); hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD| DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA); DNASSERT(hResultCode == DPNERR_BUFFERTOOSMALL); dwAppDescInfoSize = packedBuffer.GetSizeRequired();
//
// Create packed buffer to send to other players
//
if ((hResultCode = RefCountBufferNew(pdnObject,dwAppDescInfoSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create CountBuffer"); DisplayDNError(0,hResultCode); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD| DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA); if (hResultCode != DPN_OK) { DPFERR("Could not pack Application Description into buffer"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Notify other players
//
DPFX(DPFPREP, 5,"Adding UpdateApplicationDesc to Job Queue"); if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) == DPN_OK) { pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_UPDATE_APPLICATION_DESC ); pWorkerJob->SetSendNameTableOperationVersion( 0 ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL; } else { DPFERR("Could not create worker job - ignore and continue"); DisplayDNError(0,hResultCode); }
pRefCountBuffer->Release(); pRefCountBuffer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNTerminateSession"
HRESULT DNTerminateSession(DIRECTNETOBJECT *const pdnObject, const HRESULT hrReason) { HRESULT hResultCode; #ifndef DPNBUILD_NOLOBBY
BOOL fWasConnected; #endif // ! DPNBUILD_NOLOBBY
#ifndef DPNBUILD_SINGLEPROCESS
BOOL fWasRegistered; #endif // ! DPNBUILD_SINGLEPROCESS
CAsyncOp *pAsyncOp;
DPFX(DPFPREP, 4,"Parameters: hrReason [0x%lx]",hrReason);
DNASSERT(pdnObject != NULL); DNASSERT( (hrReason == DPN_OK) || (hrReason == DPNERR_HOSTTERMINATEDSESSION) || (hrReason == DPNERR_CONNECTIONLOST));
pAsyncOp = NULL;
//
// Shut down listen(s)
//
DPFX(DPFPREP, 3,"Checking LISTENs"); DNEnterCriticalSection(&pdnObject->csDirectNetObject); pAsyncOp = pdnObject->pListenParent; pdnObject->pListenParent = NULL; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp) { DPFX(DPFPREP, 3,"Canceling LISTENs"); hResultCode = DNCancelChildren(pdnObject,pAsyncOp); DPFX(DPFPREP, 3,"Canceling LISTENs returned [0x%lx]",hResultCode);
pAsyncOp->Release(); pAsyncOp = NULL; }
#ifndef DPNBUILD_SINGLEPROCESS
//
// Unregister from DPNSVR (if required)
//
fWasRegistered = FALSE; DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & DN_OBJECT_FLAG_DPNSVR_REGISTERED) { pdnObject->dwFlags &= (~DN_OBJECT_FLAG_DPNSVR_REGISTERED); fWasRegistered = TRUE; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if (fWasRegistered) { pdnObject->ApplicationDesc.UnregisterWithDPNSVR(); } #endif // ! DPNBUILD_SINGLEPROCESS
//
// Flag DirectNetObject as disconnecting. This flag will be cleared when Close() finishes.
//
#ifndef DPNBUILD_NOLOBBY
fWasConnected = FALSE; #endif // ! DPNBUILD_NOLOBBY
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) { #ifndef DPNBUILD_NOLOBBY
fWasConnected = TRUE; #endif // ! DPNBUILD_NOLOBBY
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTED); } #pragma BUGBUG( minara,"How usefull is this DN_OBJECT_FLAG_DISCONNECTING flag ?" )
pdnObject->dwFlags |= DN_OBJECT_FLAG_DISCONNECTING; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifndef DPNBUILD_NOLOBBY
//
// Update Lobby status
//
if (fWasConnected) { DNUpdateLobbyStatus(pdnObject,DPLSESSION_DISCONNECTED); } #endif // ! DPNBUILD_NOLOBBY
#ifndef DPNBUILD_NOVOICE
//
// Notify Voice
//
Voice_Notify( pdnObject, DVEVENT_STOPSESSION, 0, 0 ); #endif // DPNBUILD_NOVOICE
//
// Remove host migration target
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pNewHost) { pdnObject->pNewHost->Release(); pdnObject->pNewHost = NULL; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Delete all players from NameTable. This will involve
// emptying the table and removing short-cut player pointers
//
DPFX(DPFPREP, 5,"Removing players from NameTable"); pdnObject->NameTable.EmptyTable(hrReason);
//
// Clean up NameTable operation list
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { DPFX(DPFPREP, 5,"Cleaning up NameTable operation list"); DNNTRemoveOperations(pdnObject,0,TRUE); }
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
//
// Clean up CONNECT parent
//
if (pdnObject->pConnectParent) { pAsyncOp = pdnObject->pConnectParent; pdnObject->pConnectParent = NULL; }
//
// Clean up CONNECT info and address
//
if (pdnObject->pvConnectData) { DNFree(pdnObject->pvConnectData); pdnObject->pvConnectData = NULL; pdnObject->dwConnectDataSize = 0; } if (pdnObject->pConnectAddress) { IDirectPlay8Address_Release(pdnObject->pConnectAddress); pdnObject->pConnectAddress = NULL; } if (pdnObject->pIDP8ADevice) { IDirectPlay8Address_Release(pdnObject->pIDP8ADevice); pdnObject->pIDP8ADevice = NULL; }
//
// Clear the DISCONNECTING and HOST_CONNECTED flag
// and clear connection info
//
pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_DISCONNECTING | DN_OBJECT_FLAG_HOST_CONNECTED));
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pAsyncOp) { pAsyncOp->Release(); pAsyncOp = NULL; }
hResultCode = DPN_OK;
DNASSERT(pAsyncOp == NULL);
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_SendTo"
STDMETHODIMP DN_SendTo( PVOID pv, const DPNID dpnid, const DPN_BUFFER_DESC *const prgBufferDesc, const DWORD cBufferDesc, const DWORD dwTimeOut, void *const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) { HRESULT hResultCode; HRESULT hrSend; CNameTableEntry *pNTEntry; CNameTableEntry *pLocalPlayer; DIRECTNETOBJECT *pdnObject; DWORD dwSendFlags; CSyncEvent *pSyncEvent; const DPN_BUFFER_DESC *pActualBufferDesc; DWORD dwActualBufferDesc; CRefCountBuffer *pRefCountBuffer; DPNHANDLE handle; CAsyncOp *pAsyncOp; CAsyncOp *pParent; CAsyncOp *pHandleParent; CConnection *pConnection;
DPFX(DPFPREP, 2,"Parameters: dpnid [0x%lx], prgBufferDesc [0x%p], dwTimeOut [%ld], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]", dpnid,prgBufferDesc,dwTimeOut,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateSendParams( pv , prgBufferDesc, cBufferDesc, dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags ) ) ) { DPFX(DPFPREP, 0, "Error validating common send params hr=[0x%lx]", hResultCode ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR( "Object has not yet completed connecting / hosting" ); DPF_RETURN(DPNERR_CONNECTING); }
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("Object is not connected or hosting" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pRefCountBuffer = NULL; pSyncEvent = NULL; pNTEntry = NULL; pLocalPlayer = NULL; pAsyncOp = NULL; pParent = NULL; pHandleParent = NULL; pConnection = NULL; handle = 0;
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT) { if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pNTEntry )) != DPN_OK) { DPFERR("Could not find Host player"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get Connection reference"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_CONNECTIONLOST; // re-map this
goto Failure; }
pNTEntry->Release(); pNTEntry = NULL; } #ifndef DPNBUILD_NOMULTICAST
else if (pdnObject->dwFlags & DN_OBJECT_FLAG_MULTICAST) { if (pdnObject->pMulticastSend == NULL) { DPFERR("Could not get multicast send connection"); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pdnObject->pMulticastSend->AddRef(); pConnection = pdnObject->pMulticastSend; } #endif // ! DPNBUILD_NOMULTICAST
else { if (dpnid == DPNID_ALL_PLAYERS_GROUP) { if ((hResultCode = pdnObject->NameTable.GetAllPlayersGroupRef( &pNTEntry )) != DPN_OK) { DPFERR("Unable to get all players group"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } } else { if (dwFlags & DPNSEND_NOLOOPBACK) { if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_GENERIC; goto Failure; } if (dpnid == pLocalPlayer->GetDPNID()) { hResultCode = DPNERR_INVALIDPARAM; goto Failure; } pLocalPlayer->Release(); pLocalPlayer = NULL; }
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Unable to find target player or group"); DisplayDNError(0,hResultCode); //
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find target in deleted list either"); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Target was found, but is not reachable
//
hResultCode = DPNERR_CONNECTIONLOST; goto Failure; }
if (! pNTEntry->IsGroup()) { if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get Connection reference"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_CONNECTIONLOST; // re-map this
goto Failure; } pNTEntry->Release(); pNTEntry = NULL; } } }
//
// Create copy of data in scatter-gather buffers
//
if (!(dwFlags & (DPNSEND_NOCOPY | DPNSEND_COMPLETEONPROCESS))) { DWORD dw; DWORD dwSize;
dwSize = 0; for ( dw = 0 ; dw < cBufferDesc ; dw++ ) { dwSize += prgBufferDesc[dw].dwBufferSize; }
if ((hResultCode = RefCountBufferNew(pdnObject,dwSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not allocate buffer"); DisplayDNError(0,hResultCode); goto Failure; }
pActualBufferDesc = pRefCountBuffer->BufferDescAddress(); dwActualBufferDesc = 1; dwSize = 0; for ( dw = 0 ; dw < cBufferDesc ; dw++ ) { memcpy(pActualBufferDesc->pBufferData + dwSize,prgBufferDesc[dw].pBufferData,prgBufferDesc[dw].dwBufferSize); dwSize += prgBufferDesc[dw].dwBufferSize; } } else { pRefCountBuffer = NULL; pActualBufferDesc = prgBufferDesc; dwActualBufferDesc = cBufferDesc; }
dwSendFlags = 0; if (dwFlags & DPNSEND_GUARANTEED) { dwSendFlags |= DN_SENDFLAGS_RELIABLE; } if (dwFlags & DPNSEND_NONSEQUENTIAL) { dwSendFlags |= DN_SENDFLAGS_NON_SEQUENTIAL; } if (dwFlags & DPNSEND_PRIORITY_HIGH) { dwSendFlags |= DN_SENDFLAGS_HIGH_PRIORITY; } if (dwFlags & DPNSEND_PRIORITY_LOW) { dwSendFlags |= DN_SENDFLAGS_LOW_PRIORITY; } #ifdef DIRECTPLAYDIRECTX9
if (dwFlags & DPNSEND_COALESCE) { dwSendFlags |= DN_SENDFLAGS_COALESCE; } #endif // DIRECTPLAYDIRECTX9
if (dwFlags & DPNSEND_SYNC) { //
// Create SyncEvent for SYNC operation
//
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK) { DPFERR("Could not create sync event for group sends"); DisplayDNError(0,hResultCode); goto Failure; } } else { //
// Create Handle for ASYNC operation
//
if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create AsyncOp"); DisplayDNError(0,hResultCode); goto Failure; }
pHandleParent->SetContext( pvAsyncContext ); pHandleParent->SetStartTime( GETTIMESTAMP() ); handle = pHandleParent->GetHandle(); }
//
// pNTEntry will be NULL if this is not a group send
// pConnection will not be NULL if this is not a group send
//
if (pNTEntry != NULL) { BOOL fRequest; BOOL fNoLoopBack;
DNASSERT(pConnection == NULL); //
// Perform group sends and get parent AsyncOp
//
if (dwFlags & DPNSEND_COMPLETEONPROCESS) { fRequest = TRUE; } else { fRequest = FALSE; } if (dwFlags & DPNSEND_NOLOOPBACK) { fNoLoopBack = TRUE; } else { fNoLoopBack = FALSE; } hResultCode = DNSendGroupMessage( pdnObject, pNTEntry, DN_MSG_USER_SEND, pActualBufferDesc, dwActualBufferDesc, pRefCountBuffer, dwTimeOut, dwSendFlags, fNoLoopBack, fRequest, pHandleParent, &pParent);
if (hResultCode != DPN_OK) { DPFERR("SEND failed"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Synchronous ?
//
if (dwFlags & DPNSEND_SYNC) { pParent->SetSyncEvent( pSyncEvent ); pParent->SetResultPointer( &hrSend ); hrSend = DPNERR_GENERIC; } else { //
// Set async completion (if required). We will only need this if the SEND succeeded.
//
if (!(dwFlags & DPNSEND_NOCOMPLETE)) { pHandleParent->SetCompletion( DNCompleteSendHandle ); } pHandleParent->Release(); pHandleParent = NULL; }
pParent->Release(); pParent = NULL; pNTEntry->Release(); pNTEntry = NULL; } else { DNASSERT(pConnection != NULL); if (dwFlags & DPNSEND_COMPLETEONPROCESS) { hResultCode = DNPerformRequest( pdnObject, DN_MSG_INTERNAL_REQ_PROCESS_COMPLETION, pActualBufferDesc, pConnection, pHandleParent, &pAsyncOp); } else { hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_USER_SEND, dpnid, pActualBufferDesc, dwActualBufferDesc, pRefCountBuffer, dwTimeOut, dwSendFlags, pHandleParent, &pAsyncOp); }
pConnection->Release(); pConnection = NULL;
if (hResultCode == DPN_OK) { //
// If the caller wants asynchronous, we want to guarantee that we'll always
// return DPNSUCCESS_PENDING, but since the send is already complete,
// manually generate the completion now.
// If the caller wanted synchronous, trigger the event so we drop out of
// the wait below.
//
if (dwFlags & DPNSEND_SYNC) { pSyncEvent->Set(); hrSend = DPN_OK; } else { //
// Immediate completion should only happen for non-guaranteed sends
// where we wouldn't be told of the RTT and retry count anyway.
//
DNASSERT(! (dwFlags & DPNSEND_GUARANTEED)); DNUserSendComplete( pdnObject, handle, pvAsyncContext, pHandleParent->GetStartTime(), DPN_OK, -1, 0); pHandleParent->Release(); pHandleParent = NULL; } } else { if (hResultCode != DPNERR_PENDING) { DPFERR("SEND failed"); DisplayDNError(0,hResultCode); if (hResultCode == DPNERR_INVALIDENDPOINT) { hResultCode = DPNERR_CONNECTIONLOST; } goto Failure; }
//
// Synchronous ?
//
if (dwFlags & DPNSEND_SYNC) { pAsyncOp->SetSyncEvent( pSyncEvent ); pAsyncOp->SetResultPointer( &hrSend ); hrSend = DPNERR_GENERIC; #pragma TODO( minara, "We can be smarter about passing back errors - at least better than this !" )
} else { //
// Set async completion (if required). We will only need this if the SEND succeeded.
//
if (!(dwFlags & DPNSEND_NOCOMPLETE)) { pHandleParent->SetCompletion( DNCompleteSendHandle ); } pHandleParent->Release(); pHandleParent = NULL; }
pAsyncOp->Release(); pAsyncOp = NULL; } }
if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
if (dwFlags & DPNSEND_SYNC) { pSyncEvent->WaitForEvent(); pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL; hResultCode = hrSend; } else { if (phAsyncHandle != NULL) { *phAsyncHandle = handle; } hResultCode = DPNERR_PENDING; }
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pAsyncOp) { pAsyncOp->Release(); pAsyncOp = NULL; } if (pParent) { pParent->Release(); pParent = NULL; } if (handle != 0) { if (SUCCEEDED(pdnObject->HandleTable.Destroy( handle, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); pAsyncOp = NULL; } handle = 0; } if (pSyncEvent) { pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } goto Exit; }
// DN_Host
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Host"
STDMETHODIMP DN_Host( PVOID pInterface, const DPN_APPLICATION_DESC *const pdnAppDesc, IDirectPlay8Address **const prgpDeviceInfo, const DWORD cDeviceInfo, const DPN_SECURITY_DESC *const pdnSecurity, const DPN_SECURITY_CREDENTIALS *const pdnCredentials, void *const pvPlayerContext, const DWORD dwFlags) { CNameTableEntry *pHostPlayer; CNameTableEntry *pAllPlayersGroup; DWORD dwCurrentDevice; HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; IDirectPlay8Address *rgIDevice[MAX_HOST_ADDRESSES]; DWORD dwNumDeviceAddresses; DWORD dwListensRunning; CConnection *pConnection; CAsyncOp *pListenParent; DWORD dwEnumFrameSize; DWORD dwListenFlags; DWORD dwUpdateFlags;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdnAppDesc [0x%p], prgpDeviceInfo [0x%p], cDeviceInfo [%ld], pdnSecurity [0x%p], pdnCredentials [0x%p], dwFlags [0x%lx]", pInterface,pdnAppDesc,prgpDeviceInfo,cDeviceInfo,pdnSecurity,pdnCredentials,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateHost( pInterface, pdnAppDesc, prgpDeviceInfo, cDeviceInfo, pdnSecurity, pdnCredentials, pvPlayerContext, dwFlags ) ) ) { DPFERR( "Error validating host params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
// Check to ensure not already connected
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) { if( DN_CHECK_LOCALHOST( pdnObject ) ) { DPFERR("Object is already hosting" ); DPF_RETURN(DPNERR_HOSTING); } else { DPFERR("Object is already connected" ); DPF_RETURN(DPNERR_ALREADYCONNECTED); } }
#ifndef DPNBUILD_NOPARAMVAL
if((pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) && (pdnAppDesc->dwFlags & DPNSESSION_CLIENT_SERVER) ) { DPFERR( "You cannot specify the clientserver flag in peer mode" ); DPF_RETURN(DPNERR_INVALIDPARAM); }
#ifndef DPNBUILD_NOSERVER
if((pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) && !(pdnAppDesc->dwFlags & DPNSESSION_CLIENT_SERVER) ) { DPFERR( "You MUST specify the client/server flag for client/server mode" ); DPF_RETURN(DPNERR_INVALIDPARAM); } #endif // !DPNBUILD_NOSERVER
#endif // !DPNBUILD_NOPARAMVAL
#ifdef DIRECTPLAYDIRECTX9
//ensure that both types of signing aren't specified
if ((pdnAppDesc->dwFlags & DPNSESSION_FAST_SIGNED) && (pdnAppDesc->dwFlags & DPNSESSION_FULL_SIGNED)) { DPFERR( "You cannot specify both fast and full signing" ); DPF_RETURN(DPNERR_INVALIDPARAM); } #endif // DIRECTPLAYDIRECTX9
dwNumDeviceAddresses = 0; pListenParent = NULL; pConnection = NULL; pHostPlayer = NULL; pAllPlayersGroup = NULL;
//
// Flag as CONNECTING to prevent other operations here
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_CONNECTED)) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); hResultCode = DPNERR_ALREADYCONNECTED; goto Failure; } pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTING;
// Adding local host flag
pdnObject->dwFlags |= DN_OBJECT_FLAG_LOCALHOST; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); //
// Copy application description to DirectNet object
//
pdnObject->ApplicationDesc.Lock(); hResultCode = pdnObject->ApplicationDesc.Update(pdnAppDesc,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD| DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA|DN_APPDESCINFO_FLAG_GUIDS); pdnObject->ApplicationDesc.Unlock(); if (hResultCode != DPN_OK) { DPFERR("Could not update application description"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Create Instance GUID
//
if ((hResultCode = pdnObject->ApplicationDesc.CreateNewInstanceGuid()) != DPN_OK) { DPFERR("Could not create instance GUID - ignore and continue"); DisplayDNError(0,hResultCode); }
//
// Set NameTable DPNID mask
//
DPFX(DPFPREP, 5,"DPNID Mask [0x%lx]",pdnObject->ApplicationDesc.GetDPNIDMask()); pdnObject->NameTable.SetDPNIDMask( pdnObject->ApplicationDesc.GetDPNIDMask() );
//
// Create group "ALL PLAYERS"
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pAllPlayersGroup)) != DPN_OK) { DPFERR("Could not create NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pAllPlayersGroup->MakeGroup();
// This function takes the lock internally
pdnObject->NameTable.MakeAllPlayersGroup(pAllPlayersGroup);
//
// Create local player
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pHostPlayer)) != DPN_OK) { DPFERR("Could not create NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// This function takes the lock internally
pHostPlayer->UpdateEntryInfo( pdnObject->NameTable.GetDefaultPlayer()->GetName(), pdnObject->NameTable.GetDefaultPlayer()->GetNameSize(), pdnObject->NameTable.GetDefaultPlayer()->GetData(), pdnObject->NameTable.GetDefaultPlayer()->GetDataSize(), DPNINFO_NAME|DPNINFO_DATA, FALSE);
pHostPlayer->SetDNETVersion( DN_VERSION_CURRENT );
#ifndef DPNBUILD_NOSERVER
if (pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) { pHostPlayer->MakeServer(); } else #endif // !DPNBUILD_NOSERVER
{ DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_PEER); pHostPlayer->MakePeer(); }
pHostPlayer->SetContext(pvPlayerContext); pHostPlayer->StartConnecting();
if ((hResultCode = pdnObject->NameTable.AddEntry(pHostPlayer)) != DPN_OK) { DPFERR("Could not add NameTableEntry to NameTable"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// Create Host's connection (NULL end point)
if ((hResultCode = ConnectionNew(pdnObject,&pConnection)) != DPN_OK) { DPFERR("Could not create new connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pConnection->SetStatus( CONNECTED ); pConnection->MakeLocal(); pConnection->SetEndPt(NULL); pConnection->SetDPNID(pHostPlayer->GetDPNID());
pdnObject->NameTable.MakeLocalPlayer(pHostPlayer); pdnObject->NameTable.MakeHostPlayer(pHostPlayer);
//
// Make ALL_PLAYERS group available (does not indicate anything to user).
//
pAllPlayersGroup->Lock(); pAllPlayersGroup->MakeAvailable(); pAllPlayersGroup->Unlock(); pAllPlayersGroup->Release(); pAllPlayersGroup = NULL;
//
// Don't notify user of CREATE_PLAYER yet in case starting listens fails.
// This prevents them from having to handle CREATE_PLAYERs even in
// the failure case.
//
//
// Start listens
//
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_ONLYONEADAPTER)))
if (cDeviceInfo == 0) { //
// Create a placeholder device address
//
#ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address, reinterpret_cast<void**>(&rgIDevice[0])); #else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>(&rgIDevice[0]), FALSE); #endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK) { DPFERR("Could not create device address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
dwNumDeviceAddresses = 1; } else #endif // DPNBUILD_ONLYONESP and DPNBUILD_ONLYONEADAPTER
{ #ifdef DBG
for (dwCurrentDevice = 0 ; dwCurrentDevice < cDeviceInfo ; dwCurrentDevice++) { DPFX(DPFPREP, 5,"Original Device: prgpDeviceInfo[%ld] [0x%p]",dwCurrentDevice,prgpDeviceInfo[dwCurrentDevice]); } #endif // DBG
// Duplicate address interfaces
for (dwCurrentDevice = 0 ; dwCurrentDevice < cDeviceInfo ; dwCurrentDevice++) { if ((hResultCode = IDirectPlay8Address_Duplicate(prgpDeviceInfo[dwCurrentDevice],&rgIDevice[dwNumDeviceAddresses])) != DPN_OK) { DPFERR("Could not duplicate Host address info - skipping it"); continue; }
DPFX(DPFPREP, 5,"Duplicate Device: rgIDevice[%ld] [0x%p]",dwNumDeviceAddresses,rgIDevice[dwNumDeviceAddresses]); dwNumDeviceAddresses++; } }
// Parent Async Op
if ((hResultCode = AsyncOpNew(pdnObject,&pListenParent)) != DPN_OK) { DPFERR("Could not create AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pListenParent->SetOpType( ASYNC_OP_LISTEN ); pListenParent->MakeParent(); pListenParent->SetCompletion( DNCompleteListen );
dwListenFlags = 0; #ifndef DPNBUILD_NOSPUI
// Save query for addressing flag (if necessary)
if (dwFlags & DPNHOST_OKTOQUERYFORADDRESSING) { dwListenFlags |= DN_LISTENFLAGS_OKTOQUERYFORADDRESSING; } #endif // ! DPNBUILD_NOSPUI
if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0) { dwListenFlags |= DN_LISTENFLAGS_SESSIONDATA; } #ifdef DIRECTPLAYDIRECTX9
// Disallow enums if required
if (pdnAppDesc->dwFlags & DPNSESSION_NOENUMS) { dwListenFlags |= DN_LISTENFLAGS_DISALLOWENUMS; DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags |= DN_OBJECT_FLAG_DISALLOW_ENUMS; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); } // turning signing on if required. N.B. We've already ensured that only one of these options is selected
if (pdnAppDesc->dwFlags & DPNSESSION_FAST_SIGNED) { dwListenFlags|=DN_LISTENFLAGS_FASTSIGNED; } else if (pdnAppDesc->dwFlags & DPNSESSION_FULL_SIGNED) { dwListenFlags|=DN_LISTENFLAGS_FULLSIGNED; } #endif // DIRECTPLAYDIRECTX9
pListenParent->SetOpFlags(dwListenFlags);
// Children op's
dwListensRunning = 0; for (dwCurrentDevice = 0 ; dwCurrentDevice < dwNumDeviceAddresses ; dwCurrentDevice++) { if (rgIDevice[dwCurrentDevice] != NULL) { hResultCode = DNPerformSPListen(pdnObject, rgIDevice[dwCurrentDevice], pListenParent, NULL); if (hResultCode == DPN_OK) { dwListensRunning++; } } }
// Make sure at least 1 listen started
if (dwListensRunning == 0) { DPFERR("Could not start any LISTENs"); hResultCode = DPNERR_INVALIDDEVICEADDRESS; goto Failure; }
// Store parent LISTEN on DirectNet object
pListenParent->AddRef(); DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->pListenParent = pListenParent; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pListenParent->Release(); pListenParent = NULL;
//
// Use cached max enum frame size
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); dwEnumFrameSize = pdnObject->dwMaxFrameSize; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); DNASSERT( dwEnumFrameSize >= (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)) ); if (dwEnumFrameSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO) + pdnAppDesc->dwApplicationReservedDataSize)) { DPFERR("Not enough room for the application reserved data"); hResultCode = DPNERR_DATATOOLARGE; goto Failure; }
//
// Register with DPNSVR
//
dwUpdateFlags = 0; #ifndef DPNBUILD_SINGLEPROCESS
if(pdnObject->ApplicationDesc.UseDPNSVR()) { dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DPNSVR; } #endif // ! DPNBUILD_SINGLEPROCESS
if (pdnObject->ApplicationDesc.DisallowEnums()) { dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS; } if (dwUpdateFlags) { if ((hResultCode = DNUpdateListens(pdnObject,dwUpdateFlags)) != DPN_OK) { DPFERR("Could not update listens or register with DPNSVR"); DisplayDNError(0,hResultCode); goto Failure; } }
//
// Update DirectNet object to be connected
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING); pdnObject->dwFlags &= ~DN_OBJECT_FLAG_CONNECTING; pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
#ifndef DPNBUILD_NOLOBBY
//
// Update Lobby status
//
DNUpdateLobbyStatus(pdnObject,DPLSESSION_CONNECTED); #endif // ! DPNBUILD_NOLOBBY
//
// Now that Listens have been successfully started, indicate the local CREATE_PLAYER.
//
//
// One player in game (Local/Host player)
//
pdnObject->ApplicationDesc.IncPlayerCount(TRUE);
//
// Populate local player's connection
//
pConnection->SetDPNID(pHostPlayer->GetDPNID()); pdnObject->NameTable.PopulateConnection(pConnection); pConnection->Release(); pConnection = NULL;
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
//
// Unload SP's
//
DN_SPReleaseAll(pdnObject); #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
pHostPlayer->Release(); pHostPlayer = NULL;
hResultCode = DPN_OK;
Exit: //
// Clean up copies of device address
//
for (dwCurrentDevice = 0 ; dwCurrentDevice < dwNumDeviceAddresses ; dwCurrentDevice++) { IDirectPlay8Address_Release(rgIDevice[dwCurrentDevice]); rgIDevice[dwCurrentDevice] = NULL; }
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pListenParent) { pListenParent->Release(); pListenParent = NULL; } if (pHostPlayer) { pHostPlayer->Release(); pHostPlayer = NULL; } if (pAllPlayersGroup) { pAllPlayersGroup->Release(); pAllPlayersGroup = NULL; } DNEnterCriticalSection(&pdnObject->csDirectNetObject); pListenParent = pdnObject->pListenParent; pdnObject->pListenParent = NULL; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if (pListenParent) { DNCancelChildren(pdnObject,pListenParent); pListenParent->Release(); pListenParent = NULL; }
pdnObject->NameTable.EmptyTable(DPNERR_HOSTTERMINATEDSESSION);
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags &= ~(DN_OBJECT_FLAG_CONNECTING|DN_OBJECT_FLAG_CONNECTED|DN_OBJECT_FLAG_LOCALHOST); DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_CreateGroup"
STDMETHODIMP DN_CreateGroup(PVOID pInterface, const DPN_GROUP_INFO *const pdpnGroupInfo, void *const pvGroupContext, void *const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; DPNHANDLE hAsyncOp; PWSTR pwszName; DWORD dwNameSize; PVOID pvData; DWORD dwDataSize; CNameTableEntry *pLocalPlayer;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pdpnGroupInfo [0x%p], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]", pInterface,pdpnGroupInfo,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateCreateGroup( pInterface, pdpnGroupInfo, pvGroupContext, pvAsyncContext,phAsyncHandle, dwFlags ) ) ) { DPFERR( "Error validating create group params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to create a group" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pLocalPlayer = NULL;
if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_NAME) && (pdpnGroupInfo->pwszName)) { pwszName = pdpnGroupInfo->pwszName; dwNameSize = (wcslen(pwszName) + 1) * sizeof(WCHAR); } else { pwszName = NULL; dwNameSize = 0; } if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_DATA) && (pdpnGroupInfo->pvData) && (pdpnGroupInfo->dwDataSize)) { pvData = pdpnGroupInfo->pvData; dwDataSize = pdpnGroupInfo->dwDataSize; } else { pvData = NULL; dwDataSize = 0; }
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if (pLocalPlayer->IsHost()) { DPFX(DPFPREP, 3,"Host is creating group"); hResultCode = DNHostCreateGroup(pdnObject, pwszName, dwNameSize, pvData, dwDataSize, pdpnGroupInfo->dwInfoFlags, pdpnGroupInfo->dwGroupFlags, pvGroupContext, pvAsyncContext, pLocalPlayer->GetDPNID(), 0, &hAsyncOp, dwFlags); if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING)) { DPFERR("Could not request host to create group"); } else { if (!(dwFlags & DPNCREATEGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); pAsyncOp = NULL; } hAsyncOp = 0; } } } else { DPFX(DPFPREP, 3,"Request host to create group");
hResultCode = DNRequestCreateGroup( pdnObject, pwszName, dwNameSize, pvData, dwDataSize, pdpnGroupInfo->dwGroupFlags, pvGroupContext, pvAsyncContext, &hAsyncOp, dwFlags); if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING)) { DPFERR("Could not request host to create group"); hResultCode = DPNERR_GENERIC; #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
} else { if (!(dwFlags & DPNCREATEGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp; } } }
pLocalPlayer->Release(); pLocalPlayer = NULL;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_DestroyGroup"
STDMETHODIMP DN_DestroyGroup(PVOID pInterface, const DPNID dpnidGroup, PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; DPNHANDLE hAsyncOp; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]", pInterface,dpnidGroup,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateDestroyGroup( pInterface, dpnidGroup, pvAsyncContext, phAsyncHandle, dwFlags ) ) ) { DPFERR( "Error validating destroy group params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to destroy a group" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pLocalPlayer = NULL; pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK) { DPFERR( "Could not find specified group" ); DisplayDNError(0,hResultCode); //
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnidGroup,&pNTEntry)) != DPN_OK) { hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pNTEntry->Release(); pNTEntry = NULL; hResultCode = DPNERR_CONNECTIONLOST; goto Failure;
} if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup()) { hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if (pLocalPlayer->IsHost()) { DPFX(DPFPREP, 3,"Host is destroying group"); hResultCode = DNHostDestroyGroup( pdnObject, dpnidGroup, pvAsyncContext, pLocalPlayer->GetDPNID(), 0, &hAsyncOp, dwFlags); if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING)) { DPFERR("Could not request host to destroy group"); } else { if (!(dwFlags & DPNDESTROYGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); pAsyncOp = NULL; } hAsyncOp = 0; } } } else { DPFX(DPFPREP, 3,"Request host to destroy group");
hResultCode = DNRequestDestroyGroup(pdnObject, dpnidGroup, pvAsyncContext, &hAsyncOp, dwFlags); if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING) { DPFERR("Could not request host to destroy group"); hResultCode = DPNERR_GENERIC; #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
} else { if (!(dwFlags & DPNDESTROYGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp; } } } pLocalPlayer->Release(); pLocalPlayer = NULL;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_AddClientToGroup"
STDMETHODIMP DN_AddClientToGroup(PVOID pInterface, const DPNID dpnidGroup, const DPNID dpnidClient, PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; DPNHANDLE hAsyncOp; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], dpnidClient [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]", pInterface,dpnidGroup,dpnidClient,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateAddClientToGroup( pInterface, dpnidGroup, dpnidClient, pvAsyncContext, phAsyncHandle, dwFlags ) )) { DPFERR( "Error validating add client to group params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to add a player to a group" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pLocalPlayer = NULL; pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK) { DPFERR( "Unable to find specified group" ); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup()) { DPFERR( "Unable to specify client or all players group for group ID" ); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidClient,&pNTEntry)) != DPN_OK) { DPFERR( "Unable to find specified player" ); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } if (pNTEntry->IsGroup()) { DPFERR( "Specified client is a group ID" ); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if (pLocalPlayer->IsHost()) { DPFX(DPFPREP, 3,"Host is adding player to group"); hResultCode = DNHostAddPlayerToGroup( pdnObject, dpnidGroup, dpnidClient, pvAsyncContext, pLocalPlayer->GetDPNID(), 0, &hAsyncOp, dwFlags); if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING)) { DPFERR("Could not request host to add player to group"); } else { if (!(dwFlags & DPNADDPLAYERTOGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); pAsyncOp = NULL; } hAsyncOp = 0; } } } else { DPFX(DPFPREP, 3,"Request host to add player to group");
hResultCode = DNRequestAddPlayerToGroup(pdnObject, dpnidGroup, dpnidClient, pvAsyncContext, &hAsyncOp, dwFlags); if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING) { DPFERR("Could not request host to add player to group"); hResultCode = DPNERR_GENERIC; #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
} else { if (!(dwFlags & DPNADDPLAYERTOGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp; } } } pLocalPlayer->Release(); pLocalPlayer = NULL;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_RemoveClientFromGroup"
STDMETHODIMP DN_RemoveClientFromGroup(PVOID pInterface, const DPNID dpnidGroup, const DPNID dpnidClient, PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; DPNHANDLE hAsyncOp; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnidGroup [0x%lx], dpnidClient [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]", pInterface,dpnidGroup,dpnidClient,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateRemoveClientFromGroup( pInterface, dpnidGroup, dpnidClient, pvAsyncContext, phAsyncHandle, dwFlags ) )) { DPFERR( "Error validating remove client from group params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to remove a player from a group" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pLocalPlayer = NULL; pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pNTEntry)) != DPN_OK) { DPFERR( "Could not find specified group in nametable" ); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup()) { DPFERR( "Specified ID is not a valid group!" ); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidClient,&pNTEntry)) != DPN_OK) { DPFERR( "Specified client ID is not a valid client!" ); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } if (pNTEntry->IsGroup()) { DPFERR( "Specified client ID is a group!" ); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if (pLocalPlayer->IsHost()) { DPFX(DPFPREP, 3,"Host is deleting player from group"); hResultCode = DNHostDeletePlayerFromGroup( pdnObject, dpnidGroup, dpnidClient, pvAsyncContext, pLocalPlayer->GetDPNID(), 0, &hAsyncOp, dwFlags); if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING)) { DPFERR("Could not request host to delete player from group"); } else { if (!(dwFlags & DPNREMOVEPLAYERFROMGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
CAsyncOp* pAsyncOp; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); pAsyncOp = NULL; } hAsyncOp = 0; } } } else { DPFX(DPFPREP, 3,"Request host to delete player from group");
hResultCode = DNRequestDeletePlayerFromGroup(pdnObject, dpnidGroup, dpnidClient, pvAsyncContext, &hAsyncOp, dwFlags); if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING) { DPFERR("Could not request host to delete player from group"); hResultCode = DPNERR_GENERIC; #pragma BUGBUG( minara, "This operation should be queued to re-try after host migration" )
} else { if (!(dwFlags & DPNREMOVEPLAYERFROMGROUP_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp; } } } pLocalPlayer->Release(); pLocalPlayer = NULL;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
// DN_SetGroupInfo
#undef DPF_MODNAME
#define DPF_MODNAME "DN_SetGroupInfo"
STDMETHODIMP DN_SetGroupInfo( PVOID pv, const DPNID dpnid, DPN_GROUP_INFO *const pdpnGroupInfo, PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; DPNHANDLE hAsyncOp; PWSTR pwszName; DWORD dwNameSize; PVOID pvData; DWORD dwDataSize; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry;
DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]", pv,dpnid,pdpnGroupInfo,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateSetGroupInfo( pv, dpnid, pdpnGroupInfo, pvAsyncContext, phAsyncHandle, dwFlags ) ) ) { DPFERR( "Error validating set group info params" ); DPF_RETURN( hResultCode ); } } #endif // DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to set group info" ); DPF_RETURN(DPNERR_NOCONNECTION); } pLocalPlayer = NULL; pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR( "Specified ID is not a group" ); if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pNTEntry->Release(); pNTEntry = NULL; hResultCode = DPNERR_CONNECTIONLOST; goto Failure; } if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup()) { DPFERR( "Specified ID is not a valid group" ); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_NAME) && (pdpnGroupInfo->pwszName)) { pwszName = pdpnGroupInfo->pwszName; dwNameSize = (wcslen(pwszName) + 1) * sizeof(WCHAR); } else { pwszName = NULL; dwNameSize = 0; } if ((pdpnGroupInfo->dwInfoFlags & DPNINFO_DATA) && (pdpnGroupInfo->pvData) && (pdpnGroupInfo->dwDataSize)) { pvData = pdpnGroupInfo->pvData; dwDataSize = pdpnGroupInfo->dwDataSize; } else { pvData = NULL; dwDataSize = 0; }
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if (pLocalPlayer->IsHost()) { DPFX(DPFPREP, 3,"Host is updating group info"); hResultCode = DNHostUpdateInfo( pdnObject, dpnid, pwszName, dwNameSize, pvData, dwDataSize, pdpnGroupInfo->dwInfoFlags, pvAsyncContext, pLocalPlayer->GetDPNID(), 0, &hAsyncOp, dwFlags ); if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING)) { DPFERR("Could not request host to update info"); } else { if (!(dwFlags & DPNSETGROUPINFO_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp;
//
// Release Async HANDLE since this operation has already completed (!)
//
// TODO: MASONB: Why does DNHostUpdateInfo do this? This same code is duplicated
// everywhere.
CAsyncOp* pAsyncOp; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOp, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); pAsyncOp = NULL; } hAsyncOp = 0; } } } else { DPFX(DPFPREP, 3,"Request host to update group info");
hResultCode = DNRequestUpdateInfo( pdnObject, dpnid, pwszName, dwNameSize, pvData, dwDataSize, pdpnGroupInfo->dwInfoFlags, pvAsyncContext, &hAsyncOp, dwFlags); if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING) { DPFERR("Could not request host to update info"); } else { if (!(dwFlags & DPNSETGROUPINFO_SYNC)) { DPFX(DPFPREP, 3,"Async Handle [0x%lx]",hAsyncOp); *phAsyncHandle = hAsyncOp; } } } pLocalPlayer->Release(); pLocalPlayer = NULL;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
// DN_GetGroupInfo
//
// Retrieve group name and/or data from the local nametable.
//
// lpwszGroupName may be NULL to avoid retrieving group name
// pdwGroupFlags may be NULL to avoid retrieving group flags
// pvGroupData may not by NULL if *pdwDataSize is non zero
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetGroupInfo"
STDMETHODIMP DN_GetGroupInfo(PVOID pv, const DPNID dpnid, DPN_GROUP_INFO *const pdpnGroupInfo, DWORD *const pdwSize, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; CNameTableEntry *pNTEntry; CPackedBuffer packedBuffer; HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters: dpnid [0x%lx], pdpnGroupInfo [0x%p], dwFlags [0x%lx]", dpnid,pdpnGroupInfo,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateGetGroupInfo( pv, dpnid, pdpnGroupInfo, pdwSize, dwFlags ) ) ) { DPFERR( "Error validating get group info params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING)) ) { DPFERR("You must be connected / hosting to get group info" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR( "Specified group is not valid" ); if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { hResultCode = DPNERR_INVALIDGROUP; goto Failure; } } packedBuffer.Initialize(pdpnGroupInfo,*pdwSize);
pNTEntry->Lock(); if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup()) { DPFERR( "Specified ID is not a group" ); pNTEntry->Unlock(); hResultCode = DPNERR_INVALIDGROUP; goto Failure; }
hResultCode = pNTEntry->PackInfo(&packedBuffer);
pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL;
if ((hResultCode == DPN_OK) || (hResultCode == DPNERR_BUFFERTOOSMALL)) { *pdwSize = packedBuffer.GetSizeRequired(); }
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumClientsAndGroups"
STDMETHODIMP DN_EnumClientsAndGroups(PVOID pInterface, DPNID *const prgdpnid, DWORD *const pcdpnid, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; CBilink *pBilink; CNameTableEntry *pNTEntry; DWORD dwCount; DPNID *pDPNID; BOOL bEnum = TRUE; HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], prgdpnid [0x%p], pcdpnid [0x%p], dwFlags [0x%lx]", pInterface,prgdpnid,pcdpnid,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateEnumClientsAndGroups( pInterface, prgdpnid, pcdpnid, dwFlags ) ) ) { DPFERR( "Error validating enum clients and groups params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to enumerate players and groups" ); DPF_RETURN(DPNERR_NOCONNECTION); }
if (prgdpnid == NULL || *pcdpnid == 0) // Don't enum if not asked to
{ bEnum = FALSE; }
pdnObject->NameTable.ReadLock();
dwCount = 0; pDPNID = prgdpnid;
//
// Enum players
//
if (dwFlags & DPNENUM_PLAYERS) { pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext(); while (pBilink != &pdnObject->NameTable.m_bilinkPlayers) { pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
pNTEntry->Lock(); if (pNTEntry->IsAvailable()) { dwCount++; if (bEnum && (dwCount <= *pcdpnid)) { *pDPNID++ = pNTEntry->GetDPNID(); } else { bEnum = FALSE; } } pNTEntry->Unlock(); pBilink = pBilink->GetNext(); } }
//
// Enum groups
//
if (dwFlags & DPNENUM_GROUPS) { pBilink = pdnObject->NameTable.m_bilinkGroups.GetNext(); while (pBilink != &pdnObject->NameTable.m_bilinkGroups) { pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
pNTEntry->Lock(); if (pNTEntry->IsAvailable() && !pNTEntry->IsAllPlayersGroup()) { dwCount++; if (bEnum && (dwCount <= *pcdpnid)) { *pDPNID++ = pNTEntry->GetDPNID(); } else { bEnum = FALSE; } } pNTEntry->Unlock(); pBilink = pBilink->GetNext(); } }
pdnObject->NameTable.Unlock();
//
// This will NOT include players/groups in the deleted list.
// i.e. removed from the NameTable but for whom DESTROY_PLAYER/GROUP notifications have yet to be posted
//
*pcdpnid = dwCount; if (!bEnum && dwCount) { hResultCode = DPNERR_BUFFERTOOSMALL; } else { hResultCode = DPN_OK; }
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumGroupMembers"
STDMETHODIMP DN_EnumGroupMembers(PVOID pInterface, const DPNID dpnid, DPNID *const prgdpnid, DWORD *const pcdpnid, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; CNameTableEntry *pNTEntry; CGroupMember *pGroupMember; CBilink *pBilink; DWORD dwCount; DPNID *pDPNID; BOOL bOutputBufferTooSmall = FALSE; HRESULT hResultCode;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], dpnid [0x%lx], prgdpnid [0x%p], pcdpnid [0x%p], dwFlags [0x%lx]", pInterface,dpnid,prgdpnid,pcdpnid,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateEnumGroupMembers( pInterface, dpnid, prgdpnid, pcdpnid, dwFlags ) ) ) { DPFERR( "Error validating enum group params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to enumerate group members" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pNTEntry = NULL;
//
// if the user didn't supply a buffer, assume that the
// output buffer is too small
//
if ( ( prgdpnid == NULL ) || ( ( *pcdpnid ) == 0 ) ) { bOutputBufferTooSmall = TRUE; }
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find NameTableEntry"); if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { hResultCode = DPNERR_INVALIDGROUP; goto Failure; } pNTEntry->Release(); pNTEntry = NULL; hResultCode = DPNERR_CONNECTIONLOST; goto Failure; }
if (!pNTEntry->IsGroup() || pNTEntry->IsAllPlayersGroup()) { DPFERR("Not a group dpnid!"); hResultCode = DPNERR_INVALIDGROUP; goto Failure; }
pNTEntry->Lock();
dwCount = 0; pDPNID = prgdpnid;
pBilink = pNTEntry->m_bilinkMembership.GetNext(); while (pBilink != &pNTEntry->m_bilinkMembership) { pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkPlayers); dwCount++; if ( ( bOutputBufferTooSmall == FALSE ) && (dwCount <= *pcdpnid)) { *pDPNID++ = pGroupMember->GetPlayer()->GetDPNID(); } else { bOutputBufferTooSmall = TRUE; } pBilink = pBilink->GetNext(); }
pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL;
*pcdpnid = dwCount;
//
// if the user's output buffer appears to be incapable receiving
// output, double-check to make sure that the output size requirement
// isn't zero (which is really OK), before telling them that the
// output buffer is too small
//
if ( ( bOutputBufferTooSmall ) && ( dwCount != 0 ) ) { hResultCode = DPNERR_BUFFERTOOSMALL; } else { hResultCode = DPN_OK; }
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumHosts"
STDMETHODIMP DN_EnumHosts( PVOID pv, DPN_APPLICATION_DESC *const pApplicationDesc, IDirectPlay8Address *const pAddrHost, IDirectPlay8Address *const pDeviceInfo, PVOID const pUserEnumData, const DWORD dwUserEnumDataSize, const DWORD dwRetryCount, const DWORD dwRetryInterval, const DWORD dwTimeOut, PVOID const pvAsyncContext, DPNHANDLE *const pAsyncHandle, const DWORD dwFlags ) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; HRESULT hrEnum; #ifndef DPNBUILD_ONLYONESP
GUID guidSP; #endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
GUID guidAdapter; #endif // ! DPNBUILD_ONLYONEADAPTER
CAsyncOp *pParent; CAsyncOp *pHandleParent; CSyncEvent *pSyncEvent; CServiceProvider *pSP; CRefCountBuffer *pRCBuffer; DN_ENUM_QUERY_OP_DATA *pEnumQueryOpData; IDirectPlay8Address *pIHost; IDirectPlay8Address *pIDevice; DPNHANDLE handle; DPN_SP_CAPS dnSPCaps; #ifndef DPNBUILD_ONLYONEADAPTER
BOOL fEnumAdapters; #endif // ! DPNBUILD_ONLYONEADAPTER
BOOL fHosting; DWORD dwBufferCount; DWORD dwEnumQueryFlags; DWORD dwMultiplexFlag; GUID guidnull; #ifdef DBG
TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG
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]", pApplicationDesc,pAddrHost,pDeviceInfo,pUserEnumData,dwUserEnumDataSize,dwRetryCount,dwRetryInterval,dwTimeOut,pvAsyncContext,pAsyncHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateEnumHosts( pv, pApplicationDesc, pAddrHost, pDeviceInfo, pUserEnumData, dwUserEnumDataSize, dwRetryCount, dwRetryInterval, dwTimeOut, pvAsyncContext, pAsyncHandle, dwFlags ) ) ) { DPFERR( "Error validating enum hosts params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
//
// initialize
//
hResultCode = DPN_OK; pParent = NULL; pHandleParent = NULL; pSyncEvent = NULL; pRCBuffer = NULL; pSP = NULL; pIHost = NULL; pIDevice = NULL; handle = 0; dwMultiplexFlag = 0;
#ifdef DBG
if (pAddrHost) { DP8ASize = 512; IDirectPlay8Address_GetURL(pAddrHost,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 4,"Host address [%s]",DP8ABuffer); }
if (pDeviceInfo) { DP8ASize = 512; IDirectPlay8Address_GetURL(pDeviceInfo,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 4,"Device address [%s]",DP8ABuffer); } #endif // DBG
//
// Cannot ENUM if Hosting - I have no idea why, but VanceO insisted on it
//
fHosting = FALSE; DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CONNECTING)) { CNameTableEntry *pLocalPlayer;
pLocalPlayer = NULL;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) == DPN_OK) { if (pLocalPlayer->IsHost()) { fHosting = TRUE; } pLocalPlayer->Release(); pLocalPlayer = NULL; } } else { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); }
if (fHosting) { hResultCode = DPNERR_HOSTING; goto Failure; }
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_LIBINTERFACE)))
DNASSERT(pdnObject->pOnlySP != NULL); pdnObject->pOnlySP->AddRef(); pSP = pdnObject->pOnlySP; #else // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
#ifndef DPNBUILD_ONLYONESP
//
// Extract SP guid as we will probably need it
//
hResultCode = IDirectPlay8Address_GetSP(pDeviceInfo,&guidSP); if ( hResultCode != DPN_OK) { DPFERR("SP not specified in Device address"); goto Failure; } #endif // ! DPNBUILD_ONLYONESP
//
// Ensure SP specified in Device address is loaded
//
hResultCode = DN_SPEnsureLoaded(pdnObject, #ifndef DPNBUILD_ONLYONESP
&guidSP, #endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_LIBINTERFACE
NULL, #endif // ! DPNBUILD_LIBINTERFACE
&pSP); if (hResultCode != DPN_OK) { DPFERR("Could not ensure SP is loaded!"); DisplayDNError(0,hResultCode); goto Failure; } #endif // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
//
// Get SP caps to ensure payload will fit
//
if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) != DPN_OK) { DPFERR("Could not get SP caps"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Ensure payload will fit
//
if (dwUserEnumDataSize > dnSPCaps.dwMaxEnumPayloadSize) { DPFERR("User enum data is too large"); hResultCode = DPNERR_ENUMQUERYTOOLARGE; goto Failure; }
//
// Duplicate addresses for local usage (so we can modify them if neccessary
//
if (pAddrHost) { // Use supplied Host address
if ((hResultCode = IDirectPlay8Address_Duplicate(pAddrHost,&pIHost)) != DPN_OK) { DPFERR("Could not duplicate Host address"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDHOSTADDRESS; goto Failure; } } else { //
// Create new Host address and use Device SP guid
//
#ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address, reinterpret_cast<void**>(&pIHost)); #else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>(&pIHost), FALSE); #endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK) { DPFERR("Could not create Host address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
#ifndef DPNBUILD_ONLYONESP
if ((hResultCode = IDirectPlay8Address_SetSP(pIHost,&guidSP)) != DPN_OK) { DPFERR("Could not set Host address SP"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } #endif // ! DPNBUILD_ONLYONESP
}
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_ONLYONEADAPTER)))
if (pDeviceInfo == NULL) { hResultCode = IDirectPlay8Address_Duplicate(pIHost,&pIDevice); } else #endif // DPNBUILD_ONLYONESP and DPNBUILD_ONLYONEADAPTER
{ hResultCode = IDirectPlay8Address_Duplicate(pDeviceInfo,&pIDevice); } if (hResultCode != DPN_OK) { DPFERR("Could not duplicate Device address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
#ifdef DBG
DP8ASize = 512; IDirectPlay8Address_GetURL(pIHost,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 4,"Host address [%s]",DP8ABuffer);
DP8ASize = 512; IDirectPlay8Address_GetURL(pIDevice,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 4,"Device address [%s]",DP8ABuffer); #endif // DBG
// Enum flags to Protocol
dwEnumQueryFlags = 0; #ifndef DPNBUILD_NOSPUI
if (dwFlags & DPNENUMHOSTS_OKTOQUERYFORADDRESSING) { dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_OKTOQUERYFORADDRESSING; } #endif // ! DPNBUILD_NOSPUI
if (dwFlags & DPNENUMHOSTS_NOBROADCASTFALLBACK) { dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_NOBROADCASTFALLBACK; } if (pApplicationDesc->dwReservedDataSize > 0) { dwEnumQueryFlags |= DN_ENUMQUERYFLAGS_SESSIONDATA; }
//
// Parent for ENUMs
//
if ((hResultCode = AsyncOpNew(pdnObject,&pParent)) != DPN_OK) { DPFERR("Could not create ENUM parent AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pParent->MakeParent(); pParent->SetOpType( ASYNC_OP_ENUM_QUERY ); pParent->SetContext( pvAsyncContext ); pParent->SetCompletion( DNCompleteEnumQuery ); pParent->SetOpFlags( dwEnumQueryFlags );
//
// Synchronous ?
//
if (dwFlags & DPNENUMHOSTS_SYNC) { if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK) { DPFERR("Could not create SyncEvent"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pParent->SetSyncEvent( pSyncEvent ); pParent->SetResultPointer( &hrEnum ); hrEnum = DPNERR_GENERIC; } else { //
// Create Handle parent AsyncOp (if required)
//
if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pHandleParent->SetContext( pvAsyncContext ); pHandleParent->Lock(); if (pHandleParent->IsCancelled()) { pHandleParent->Unlock(); pParent->SetResult( DPNERR_USERCANCEL ); hResultCode = DPNERR_USERCANCEL; goto Failure; } pParent->MakeChild( pHandleParent ); handle = pHandleParent->GetHandle(); pHandleParent->Unlock(); }
//
// Keep SP on ENUM parent
//
pParent->SetSP( pSP ); pSP->Release(); pSP = NULL;
pEnumQueryOpData = pParent->GetLocalEnumQueryOpData(); #ifndef DPNBUILD_ONLYONEADAPTER
//
// If there is no adapter specified in the device address,
// we will attempt to enum on each individual adapter if the SP supports it
//
fEnumAdapters = FALSE; if ((hResultCode = IDirectPlay8Address_GetDevice( pIDevice, &guidAdapter )) != DPN_OK) { DPFX(DPFPREP,1,"Could not determine adapter"); DisplayDNError(1,hResultCode);
if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSALLADAPTERS) { DPFX(DPFPREP, 3,"SP supports ENUMing on all adapters"); fEnumAdapters = TRUE; } }
if(fEnumAdapters) { DWORD dwNumAdapters; GUID *pAdapterList = NULL;
if ((hResultCode = DNEnumAdapterGuids( pdnObject, #ifndef DPNBUILD_ONLYONESP
&guidSP, #endif // ! DPNBUILD_ONLYONESP
0, &pAdapterList, &dwNumAdapters)) != DPN_OK) { DPFERR("Could not enum adapters for this SP"); DisplayDNError(0,hResultCode); goto Failure; } if (dwNumAdapters == 0) { DPFERR("No adapters were found for this SP"); hResultCode = DPNERR_INVALIDDEVICEADDRESS; goto Failure; }
pEnumQueryOpData->dwNumAdapters = dwNumAdapters; pEnumQueryOpData->dwCurrentAdapter = 0;
if (dwNumAdapters > 1) { dwMultiplexFlag |= DN_ENUMQUERYFLAGS_ADDITIONALMULTIPLEXADAPTERS; } //
// Choose first adapter for initial ENUM call
//
if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice,pAdapterList)) != DPN_OK) { DPFERR("Could not set device adapter"); DisplayDNError(0,hResultCode); MemoryBlockFree(pdnObject,pAdapterList); goto Failure; } pEnumQueryOpData->dwCurrentAdapter++; pParent->SetOpData( pAdapterList ); pAdapterList = NULL; } else #endif // ! DPNBUILD_ONLYONEADAPTER
{ #ifndef DPNBUILD_ONLYONEADAPTER
pEnumQueryOpData->dwNumAdapters = 0; pEnumQueryOpData->dwCurrentAdapter = 0; #endif // ! DPNBUILD_ONLYONEADAPTER
}
//
// Set up EnumQuery BufferDescriptions
//
//
// When filling out the enum structure the SP requires an extra BUFFERDESC
// to exist immediately before the one were passing with the user data. The
// SP will be using that extra buffer to prepend an optional header
//
pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].pBufferData = reinterpret_cast<BYTE*>(&pEnumQueryOpData->EnumQueryPayload); memset(&guidnull, 0, sizeof(guidnull)); if (pApplicationDesc->guidApplication != guidnull) { 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}.", pdnObject, pApplicationDesc->guidApplication.Data1, pApplicationDesc->guidApplication.Data2, pApplicationDesc->guidApplication.Data3, pApplicationDesc->guidApplication.Data4[0], pApplicationDesc->guidApplication.Data4[1], pApplicationDesc->guidApplication.Data4[2], pApplicationDesc->guidApplication.Data4[3], pApplicationDesc->guidApplication.Data4[4], pApplicationDesc->guidApplication.Data4[5], pApplicationDesc->guidApplication.Data4[6], pApplicationDesc->guidApplication.Data4[7]);
pEnumQueryOpData->EnumQueryPayload.QueryType = DN_ENUM_QUERY_WITH_APPLICATION_GUID; memcpy(&pEnumQueryOpData->EnumQueryPayload.guidApplication,&pApplicationDesc->guidApplication,sizeof(GUID)); pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].dwBufferSize = sizeof(DN_ENUM_QUERY_PAYLOAD); } else { pEnumQueryOpData->EnumQueryPayload.QueryType = DN_ENUM_QUERY_WITHOUT_APPLICATION_GUID; pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD].dwBufferSize = sizeof(DN_ENUM_QUERY_PAYLOAD) - sizeof(GUID); }
//
// Copy user data (if any)
//
if (pUserEnumData && dwUserEnumDataSize) { DPFX(DPFPREP,3,"User enum data specified"); if ((hResultCode = RefCountBufferNew(pdnObject,dwUserEnumDataSize,MemoryBlockAlloc,MemoryBlockFree,&pRCBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); goto Failure; } memcpy(pRCBuffer->GetBufferAddress(),pUserEnumData,dwUserEnumDataSize); pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].pBufferData = reinterpret_cast<BYTE*>(pRCBuffer->GetBufferAddress()); pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].dwBufferSize = dwUserEnumDataSize; pParent->SetRefCountBuffer( pRCBuffer ); dwBufferCount = DN_ENUM_BUFFERDESC_QUERY_COUNT;
pRCBuffer->Release(); pRCBuffer = NULL; } else { DPFX(DPFPREP,3,"User enum data not specified"); pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].pBufferData = NULL; pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_USER_PAYLOAD].dwBufferSize = 0; dwBufferCount = DN_ENUM_BUFFERDESC_QUERY_COUNT - 1; }
//
// Set up EnumQuery misc fields
//
pEnumQueryOpData->dwRetryCount = dwRetryCount; pEnumQueryOpData->dwRetryInterval = dwRetryInterval; pEnumQueryOpData->dwTimeOut = dwTimeOut; pEnumQueryOpData->dwBufferCount = dwBufferCount;
//
// For reserved data we understand, we don't actually need all of the data we had the
// user track.
//
if ((pApplicationDesc->dwReservedDataSize == DPN_MAX_APPDESC_RESERVEDDATA_SIZE) && (*((DWORD*) pApplicationDesc->pvReservedData) == SPSESSIONDATAINFO_XNET)) { pEnumQueryOpData->dwAppDescReservedDataSize = sizeof(SPSESSIONDATA_XNET); memcpy(pEnumQueryOpData->AppDescReservedData, &pApplicationDesc->pvReservedData, pEnumQueryOpData->dwAppDescReservedDataSize); } else { pEnumQueryOpData->dwAppDescReservedDataSize = 0; }
DPFX(DPFPREP,3,"Number of buffers actually used [%ld]",dwBufferCount); hResultCode = DNPerformEnumQuery( pdnObject, pIHost, pIDevice, pParent->GetSP()->GetHandle(), pParent->GetOpFlags() | dwMultiplexFlag, pParent->GetContext(), pParent ); if (hResultCode != DPN_OK) { DPFERR("Could not start ENUM"); DisplayDNError(0,hResultCode); goto Failure; } pParent->Release(); pParent = NULL;
//
// Wait for SyncEvent or return Async Handle
//
if (dwFlags & DPNENUMHOSTS_SYNC) { pSyncEvent->WaitForEvent(); pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL; hResultCode = hrEnum; } else { //
// Blame vanceo if this EVER returns anything other than DPN_OK at this stage
//
pHandleParent->SetCompletion( DNCompleteAsyncHandle ); pHandleParent->Release(); pHandleParent = NULL;
*pAsyncHandle = handle; hResultCode = DPNERR_PENDING; }
IDirectPlay8Address_Release(pIDevice); pIDevice = NULL;
IDirectPlay8Address_Release(pIHost); pIHost = NULL;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (handle != 0) { CAsyncOp* pAsyncOp; if (SUCCEEDED(pdnObject->HandleTable.Destroy( handle, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); pAsyncOp = NULL; } handle = 0; } if (pParent) { pParent->Release(); pParent = NULL; } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pSyncEvent) { pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL; } if (pRCBuffer) { pRCBuffer->Release(); pRCBuffer = NULL; } if (pSP) { pSP->Release(); pSP = NULL; } if (pIHost) { IDirectPlay8Address_Release(pIHost); pIHost = NULL; } if (pIDevice) { IDirectPlay8Address_Release(pIDevice); pIDevice = NULL; } goto Exit; }
//**********************************************************************
// DN_DestroyPlayer
//
// Remove a player from this DirectNet session
// This will send a termination message to the player.
// Both the host and the player will terminate.
#undef DPF_MODNAME
#define DPF_MODNAME "DN_DestroyPlayer"
STDMETHODIMP DN_DestroyPlayer(PVOID pInterface, const DPNID dpnid, const void *const pvDestroyData, const DWORD dwDestroyDataSize, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CNameTableEntry *pNTEntry; CConnection *pConnection; DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], dpnid [0x%lx], pvDestroyData [0x%p], dwDestroyDataSize [%ld], dwFlags [0x%lx]", pInterface,dpnid,pvDestroyData,dwDestroyDataSize,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateDestroyPlayer( pInterface, dpnid, pvDestroyData, dwDestroyDataSize, dwFlags ) ) ) { DPFERR( "Error validating destroy player params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to destroy a player" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pNTEntry = NULL; pRefCountBuffer = NULL; pConnection = NULL;
if (!DN_CHECK_LOCALHOST(pdnObject)) { DPFERR( "Object is not session host, cannot destroy players" ); DPF_RETURN(DPNERR_NOTHOST); }
// Ensure DNID specified is valid
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find player entry"); DisplayDNError(0,hResultCode); if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } pNTEntry->Release(); pNTEntry = NULL; hResultCode = DPNERR_CONNECTIONLOST; goto Failure; } if (pNTEntry->IsLocal() ) { DPFERR( "Cannot destroy local player" ); hResultCode = DPNERR_INVALIDPLAYER; DisplayDNError(0,hResultCode); goto Failure; } if (pNTEntry->IsGroup()) { hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get connection ref"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_CONNECTIONLOST; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Build terminate message
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION) + dwDestroyDataSize, MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not allocate RefCountBuffer"); DisplayDNError(0,hResultCode); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pRefCountBuffer->GetBufferAddress()); if (dwDestroyDataSize) { memcpy(pMsg+1,pvDestroyData,dwDestroyDataSize); pMsg->dwTerminateDataOffset = sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION); } else { pMsg->dwTerminateDataOffset = 0; } pMsg->dwTerminateDataSize = dwDestroyDataSize;
//
// Send message to player to exit
//
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_TERMINATE_SESSION, dpnid, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL); if (hResultCode != DPNERR_PENDING) { DPFERR("Could not send DESTROY_CLIENT message to player"); DisplayDNError(0,hResultCode); DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
if (hResultCode == DPNERR_INVALIDENDPOINT) { hResultCode = DPNERR_INVALIDPLAYER; } goto Failure; }
pConnection->Release(); pConnection = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL;
//
// Remove from NameTable and inform other players of disconnect
//
hResultCode = DNHostDisconnect(pdnObject,dpnid,DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); DNASSERT(hResultCode != DPNERR_INVALIDENDPOINT); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
// DN_ReturnBuffer
//
// Return a receive buffer which is no longer in use
#undef DPF_MODNAME
#define DPF_MODNAME "DN_ReturnBuffer"
STDMETHODIMP DN_ReturnBuffer(PVOID pv, const DPNHANDLE hBufferHandle, const DWORD dwFlags) { DIRECTNETOBJECT *pdnObject; HRESULT hResultCode; CAsyncOp *pAsyncOp;
DPFX(DPFPREP, 2,"Parameters: hBufferHandle [0x%lx], dwFlags [0x%lx]",hBufferHandle,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateReturnBuffer( pv, hBufferHandle, dwFlags ) ) ) { DPFERR( "Error validating return buffer params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to return a buffer" ); DPF_RETURN(DPNERR_NOCONNECTION); }
DNASSERT( pdnObject != NULL );
pAsyncOp = NULL;
//
// Find async op
//
pdnObject->HandleTable.Lock(); if ((hResultCode = pdnObject->HandleTable.Find( hBufferHandle,(PVOID*)&pAsyncOp )) != DPN_OK) { pdnObject->HandleTable.Unlock(); DPFERR("Could not find handle"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDHANDLE; goto Failure; } else { pAsyncOp->AddRef(); pdnObject->HandleTable.Unlock(); }
//
// Ensure it's not already cancelled
//
pAsyncOp->Lock(); if (pAsyncOp->IsCancelled() || pAsyncOp->IsComplete()) { pAsyncOp->Unlock(); hResultCode = DPNERR_INVALIDHANDLE; goto Failure; } pAsyncOp->SetComplete(); pAsyncOp->Unlock();
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hBufferHandle, NULL ))) { //
// Remove from active list
//
DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOp->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList);
// Release the HandleTable reference
pAsyncOp->Release(); }
pAsyncOp->Release(); pAsyncOp = NULL;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pAsyncOp) { pAsyncOp->Release(); pAsyncOp = NULL; } goto Exit; }
// DN_GetPlayerContext
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetPlayerContext"
STDMETHODIMP DN_GetPlayerContext(PVOID pv, const DPNID dpnid, PVOID *const ppvPlayerContext, const DWORD dwFlags) { HRESULT hResultCode; CNameTableEntry *pNTEntry; DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], ppvPlayerContext [0x%p], dwFlags [0x%lx]", pv, dpnid,ppvPlayerContext,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateGetPlayerContext( pv, dpnid, ppvPlayerContext, dwFlags ) ) ) { DPFERR( "Error validating getplayercontext params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) ) { DPFERR("You must be connected / hosting to get player context" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not retrieve player entry"); DisplayDNError(0,hResultCode);
//
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find player in deleted list either"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } }
//
// Ensure this is not a group and that the player has been created
// There may be a period during which the player is "available" but the CREATE_PLAYER notification
// has not returned. Return DPNERR_NOTREADY in this case.
//
pNTEntry->Lock(); if (pNTEntry->IsGroup()) { pNTEntry->Unlock(); hResultCode = DPNERR_INVALIDPLAYER; goto Failure; } if (!pNTEntry->IsCreated()) { if (pNTEntry->IsAvailable()) { hResultCode = DPNERR_NOTREADY; } else { hResultCode = DPNERR_INVALIDPLAYER; } pNTEntry->Unlock(); goto Failure; }
*ppvPlayerContext = pNTEntry->GetContext(); pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
// DN_GetGroupContext
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetGroupContext"
STDMETHODIMP DN_GetGroupContext(PVOID pv, const DPNID dpnid, PVOID *const ppvGroupContext, const DWORD dwFlags) { HRESULT hResultCode; CNameTableEntry *pNTEntry; DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 2,"Parameters: pv [0x%p], dpnid [0x%lx], ppvGroupContext [0x%p], dwFlags [0x%lx]", pv, dpnid,ppvGroupContext,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pv)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateGetGroupContext( pv, dpnid, ppvGroupContext,dwFlags ) ) ) { DPFERR( "Error validating getgroupcontext params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) ) { DPFERR("You must be connected / hosting to get group context" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pNTEntry = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not retrieve group entry"); DisplayDNError(0,hResultCode);
//
// Try deleted list
//
if ((hResultCode = pdnObject->NameTable.FindDeletedEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find player in deleted list either"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } }
//
// Ensure this is not a player and that the group has been created
// There may be a period during which the group is "available" but the CREATE_GROUP notification
// has not returned. Return DPNERR_NOTREADY in this case.
//
pNTEntry->Lock(); if (!pNTEntry->IsGroup()) { pNTEntry->Unlock(); hResultCode = DPNERR_INVALIDGROUP; goto Failure; } if (!pNTEntry->IsCreated()) { if (pNTEntry->IsAvailable()) { hResultCode = DPNERR_NOTREADY; } else { hResultCode = DPNERR_INVALIDGROUP; } pNTEntry->Unlock(); goto Failure; }
if( pNTEntry->IsAllPlayersGroup() ) { pNTEntry->Unlock(); DPFERR("Cannot getcontext for the all players group" ); hResultCode = DPNERR_INVALIDGROUP; goto Failure; }
*ppvGroupContext = pNTEntry->GetContext(); pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DN_RegisterLobby"
STDMETHODIMP DN_RegisterLobby(PVOID pInterface, const DPNHANDLE dpnhLobbyConnection, IDirectPlay8LobbiedApplication *const pIDP8LobbiedApplication, const DWORD dwFlags) { #ifdef DPNBUILD_NOLOBBY
DPFX(DPFPREP, 0, "RegisterLobby is not supported!"); return DPNERR_UNSUPPORTED; #else // ! DPNBUILD_NOLOBBY
DIRECTNETOBJECT *pdnObject; #ifndef DPNBUILD_NOPARAMVAL
HRESULT hResultCode; #endif // DPNBUILD_NOPARAMVAL
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], pIDP8LobbiedApplication [0x%p], dwFlags [0x%lx]", pInterface,pIDP8LobbiedApplication,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateRegisterLobby( pInterface, dpnhLobbyConnection, pIDP8LobbiedApplication, dwFlags ) ) ) { DPFERR( "Error validating register lobby params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
if (dwFlags == DPNLOBBY_REGISTER) { DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); return(DPNERR_ALREADYREGISTERED); } IDirectPlay8LobbiedApplication_AddRef(pIDP8LobbiedApplication);
pdnObject->pIDP8LobbiedApplication = pIDP8LobbiedApplication; pdnObject->dpnhLobbyConnection = dpnhLobbyConnection; pdnObject->dwFlags |= DN_OBJECT_FLAG_LOBBY_AWARE; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); } else { DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE)) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); return(DPNERR_NOTREGISTERED); } IDirectPlay8LobbiedApplication_Release(pdnObject->pIDP8LobbiedApplication); pdnObject->dpnhLobbyConnection = NULL; pdnObject->pIDP8LobbiedApplication = NULL; pdnObject->dwFlags &= (~DN_OBJECT_FLAG_LOBBY_AWARE); DNLeaveCriticalSection(&pdnObject->csDirectNetObject); }
return(DPN_OK); #endif // ! DPNBUILD_NOLOBBY
}
#ifndef DPNBUILD_NOLOBBY
#undef DPF_MODNAME
#define DPF_MODNAME "DNNotifyLobbyClientOfSettings"
//
// DNNotifyLobbyClientOfSettings
//
// This function sends a connection settings update to the lobby client informing it that the lobby
// client settings have changed.
//
HRESULT DNNotifyLobbyClientOfSettings( DIRECTNETOBJECT * const pdnObject, IDirectPlay8LobbiedApplication *pdpLobbiedApp, DPNHANDLE dpnConnection, IDirectPlay8Address *pHostAddress, IDirectPlay8Address *pConnectFromAddress ) { HRESULT hResultCode = DPN_OK; DPL_CONNECTION_SETTINGS dplConnectionSettings; BOOL fIsHost = FALSE; CPackedBuffer packBuffer; PBYTE pBuffer = NULL; BOOL fINCriticalSection = FALSE; CNameTableEntry *pNTEntry = NULL; DWORD dwIndex;
fIsHost = DN_CHECK_LOCALHOST( pdnObject );
ZeroMemory( &dplConnectionSettings, sizeof( DPL_CONNECTION_SETTINGS ) ); dplConnectionSettings.dwSize = sizeof( DPL_CONNECTION_SETTINGS ); dplConnectionSettings.dwFlags = (fIsHost) ? DPLCONNECTSETTINGS_HOST : 0;
// Lock the object while we make a copy of the app desc.
DNEnterCriticalSection(&pdnObject->csDirectNetObject); fINCriticalSection = TRUE; // Determine the size of buffer
packBuffer.Initialize(NULL, 0 ); hResultCode = pdnObject->ApplicationDesc.Pack(&packBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA| DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
if( hResultCode != DPNERR_BUFFERTOOSMALL ) { DPFX(DPFPREP, 0, "Error getting app desc size hr=0x%x", hResultCode ); goto NOTIFY_EXIT; }
pBuffer = (BYTE*) DNMalloc(packBuffer.GetSizeRequired());
if( !pBuffer ) { DPFX(DPFPREP, 0, "Error allocating memory for buffer" ); hResultCode = DPNERR_OUTOFMEMORY; goto NOTIFY_EXIT; }
packBuffer.Initialize(pBuffer,packBuffer.GetSizeRequired()); hResultCode = pdnObject->ApplicationDesc.Pack(&packBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA| DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
if( FAILED( hResultCode ) ) { DPFX(DPFPREP, 0, "Error packing app desc hr=0x%x", hResultCode ); goto NOTIFY_EXIT; }
DNLeaveCriticalSection(&pdnObject->csDirectNetObject); fINCriticalSection = FALSE;
memcpy( &dplConnectionSettings.dpnAppDesc, pBuffer, sizeof( DPN_APPLICATION_DESC ) );
hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pNTEntry );
if( FAILED( hResultCode ) ) { DPFX(DPFPREP, 0, "Error getting local player hr=0x%x", hResultCode ); goto NOTIFY_EXIT; }
// Make sure player name isn't changed while we are working with the entry
pNTEntry->Lock(); if( pNTEntry->GetName() ) { dplConnectionSettings.pwszPlayerName = (WCHAR*) DNMalloc((wcslen(pNTEntry->GetName())+1)*sizeof(WCHAR));
if( !dplConnectionSettings.pwszPlayerName ) { pNTEntry->Unlock(); DPFX(DPFPREP, 0, "Error allocating memory" ); goto NOTIFY_EXIT; } wcscpy( dplConnectionSettings.pwszPlayerName, pNTEntry->GetName() ); } else { dplConnectionSettings.pwszPlayerName = NULL; } pNTEntry->Unlock();
// Release our reference
pNTEntry->Release();
// Host address field
if( fIsHost ) { dplConnectionSettings.pdp8HostAddress = NULL;
hResultCode = DNGetHostAddressHelper( pdnObject, dplConnectionSettings.ppdp8DeviceAddresses, &dplConnectionSettings.cNumDeviceAddresses );
if( hResultCode != DPNERR_BUFFERTOOSMALL ) { dplConnectionSettings.cNumDeviceAddresses = 0; DPFX(DPFPREP, 0, "Could not get host addresses for lobby update hr=0x%x", hResultCode ); goto NOTIFY_EXIT; }
dplConnectionSettings.ppdp8DeviceAddresses = (IDirectPlay8Address**) DNMalloc(dplConnectionSettings.cNumDeviceAddresses*sizeof(IDirectPlay8Address*));
if( !dplConnectionSettings.ppdp8DeviceAddresses ) { DPFX(DPFPREP, 0, "Error allocating memory" ); dplConnectionSettings.cNumDeviceAddresses = 0; hResultCode = DPNERR_OUTOFMEMORY; goto NOTIFY_EXIT; }
hResultCode = DNGetHostAddressHelper( pdnObject, dplConnectionSettings.ppdp8DeviceAddresses, &dplConnectionSettings.cNumDeviceAddresses );
if( FAILED( hResultCode ) ) { dplConnectionSettings.cNumDeviceAddresses = 0; DPFX(DPFPREP, 0, "Could not get host addresses for lobby update hr=0x%x", hResultCode ); goto NOTIFY_EXIT; } } else { dplConnectionSettings.pdp8HostAddress = pHostAddress; dplConnectionSettings.ppdp8DeviceAddresses = &pConnectFromAddress; dplConnectionSettings.cNumDeviceAddresses = 1; }
// Update the settings
hResultCode = IDirectPlay8LobbiedApplication_SetConnectionSettings( pdpLobbiedApp, dpnConnection, &dplConnectionSettings, 0 );
NOTIFY_EXIT:
if( dplConnectionSettings.ppdp8DeviceAddresses && fIsHost ) { for( dwIndex = 0; dwIndex < dplConnectionSettings.cNumDeviceAddresses; dwIndex++ ) { IDirectPlay8Address_Release( dplConnectionSettings.ppdp8DeviceAddresses[dwIndex] ); }
DNFree(dplConnectionSettings.ppdp8DeviceAddresses); }
if( dplConnectionSettings.pwszPlayerName ) DNFree(dplConnectionSettings.pwszPlayerName);
if( fINCriticalSection ) DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if( pBuffer ) DNFree(pBuffer);
return hResultCode;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNUpdateLobbyStatus"
HRESULT DNUpdateLobbyStatus(DIRECTNETOBJECT *const pdnObject, const DWORD dwStatus) { HRESULT hResultCode; IDirectPlay8LobbiedApplication *pIDP8LobbiedApplication; DPNHANDLE dpnhLobbyConnection = NULL; IDirectPlay8Address *pHostAddress = NULL; IDirectPlay8Address *pConnectFromAddress = NULL;
DPFX(DPFPREP, 4,"Parameters: dwStatus [0x%lx]",dwStatus);
DNASSERT(pdnObject != NULL);
pIDP8LobbiedApplication = NULL;
//
// Get lobbied application interface, if it exists and other settings we need
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if ((pdnObject->dwFlags & DN_OBJECT_FLAG_LOBBY_AWARE) && (pdnObject->pIDP8LobbiedApplication)) { IDirectPlay8LobbiedApplication_AddRef(pdnObject->pIDP8LobbiedApplication); pIDP8LobbiedApplication = pdnObject->pIDP8LobbiedApplication; dpnhLobbyConnection = pdnObject->dpnhLobbyConnection;
pConnectFromAddress = pdnObject->pIDP8ADevice; pHostAddress = pdnObject->pConnectAddress;
if( pConnectFromAddress ) { IDirectPlay8Address_AddRef( pConnectFromAddress ); }
if( pHostAddress ) { IDirectPlay8Address_AddRef( pHostAddress ); } } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Update status and release object
//
if (pIDP8LobbiedApplication) { // If we are about to do a connection notification
// we send the updated connection settings.
//
// This gives lobby client full picture.
//
if( dwStatus == DPLSESSION_CONNECTED ) { DNNotifyLobbyClientOfSettings(pdnObject, pIDP8LobbiedApplication, dpnhLobbyConnection, pHostAddress, pConnectFromAddress ); }
IDirectPlay8LobbiedApplication_UpdateStatus(pIDP8LobbiedApplication,dpnhLobbyConnection,dwStatus,0);
IDirectPlay8LobbiedApplication_Release(pIDP8LobbiedApplication); pIDP8LobbiedApplication = NULL;
if( pHostAddress ) { IDirectPlay8Address_Release( pHostAddress ); }
if( pConnectFromAddress ) { IDirectPlay8Address_Release( pConnectFromAddress ); } }
hResultCode = DPN_OK;
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
#endif // ! DPNBUILD_NOLOBBY
#undef DPF_MODNAME
#define DPF_MODNAME "DN_TerminateSession"
STDMETHODIMP DN_TerminateSession(PVOID pInterface, void *const pvTerminateData, const DWORD dwTerminateDataSize, const DWORD dwFlags) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; CRefCountBuffer *pRefCountBuffer; CWorkerJob *pWorkerJob; DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pvTerminateData [0x%p], dwTerminateDataSize [%ld], dwFlags [0x%lx]", pInterface,pvTerminateData,dwTerminateDataSize,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateTerminateSession( pInterface, pvTerminateData, dwTerminateDataSize, dwFlags ) ) ) { DPFERR( "Error validating terminatesession params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to terminate a session" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pRefCountBuffer = NULL; pWorkerJob = NULL;
if (!DN_CHECK_LOCALHOST(pdnObject)) { DPFERR( "Object is not session host, cannot destroy players" ); hResultCode = DPNERR_NOTHOST; goto Failure; }
//
// Build terminate message
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION) + dwTerminateDataSize, MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not allocate RefCountBuffer"); DisplayDNError(0,hResultCode); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pRefCountBuffer->GetBufferAddress()); if (dwTerminateDataSize) { memcpy(pMsg+1,pvTerminateData,dwTerminateDataSize); pMsg->dwTerminateDataOffset = sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION); } else { pMsg->dwTerminateDataOffset = 0; } pMsg->dwTerminateDataSize = dwTerminateDataSize;
//
// Worker job to send message to all players
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not allocate new WorkerJob"); DisplayDNError(0,hResultCode); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_TERMINATE_SESSION ); pWorkerJob->SetSendNameTableOperationVersion( 0 ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL;
//
// Terminate local session
//
hResultCode = DNUserTerminateSession(pdnObject, DPNERR_HOSTTERMINATEDSESSION, pvTerminateData, dwTerminateDataSize);
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create WorkerJob"); DisplayDNError(0,hResultCode); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_TERMINATE_SESSION ); pWorkerJob->SetTerminateSessionReason( DPNERR_HOSTTERMINATEDSESSION );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
//
// FUnction that performs work for DN_GetHostAddress and for Lobby informs
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetHostAddressHelper"
HRESULT DNGetHostAddressHelper(DIRECTNETOBJECT *pdnObject, IDirectPlay8Address **const prgpAddress, DWORD *const pcAddress) { CAsyncOp *pListenParent; CAsyncOp *pListenSP; CAsyncOp *pListen; CBilink *pBilinkSP; CBilink *pBilink; DWORD dwListenCount; CNameTableEntry *pLocalPlayer; IDirectPlay8Address **ppAddress; HRESULT hResultCode;
pListenParent = NULL; pListenSP = NULL; pListen = NULL; pLocalPlayer = NULL; if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } DNEnterCriticalSection(&pdnObject->csDirectNetObject); if ( !(pdnObject->dwFlags & DN_OBJECT_FLAG_LISTENING) || !pLocalPlayer->IsHost() || (pdnObject->pListenParent == NULL))
{ DNLeaveCriticalSection(&pdnObject->csDirectNetObject); DPFERR("Not listening or Host player"); hResultCode = DPNERR_NOTHOST; goto Failure; } pdnObject->pListenParent->AddRef(); pListenParent = pdnObject->pListenParent; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Ensure that the address pointer buffer is large enough
//
dwListenCount = 0; pListenParent->Lock(); // Prevent changes while we run through
pBilinkSP = pListenParent->m_bilinkParent.GetNext(); while (pBilinkSP != &pListenParent->m_bilinkParent) { pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext(); while (pBilink != &pListenSP->m_bilinkParent) { dwListenCount++; pBilink = pBilink->GetNext(); }
pListenSP->Unlock(); pListenSP = NULL;
pBilinkSP = pBilinkSP->GetNext(); }
if (dwListenCount > *pcAddress) { pListenParent->Unlock(); *pcAddress = dwListenCount; hResultCode = DPNERR_BUFFERTOOSMALL; goto Failure; }
//
// Get addresses of LISTENs
//
ppAddress = prgpAddress; dwListenCount = 0; pBilinkSP = pListenParent->m_bilinkParent.GetNext(); while (pBilinkSP != &pListenParent->m_bilinkParent) { pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren);
pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext(); while (pBilink != &pListenSP->m_bilinkParent) { pListen = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
if (pListen->GetProtocolHandle() != NULL) { SPGETADDRESSINFODATA spInfoData;
memset(&spInfoData,0x00,sizeof(SPGETADDRESSINFODATA)); spInfoData.Flags = SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES; if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData,pListen->GetProtocolHandle(),&spInfoData)) != DPN_OK) { DPFERR("Could not get LISTEN address!"); DisplayDNError(0,hResultCode); //
// Release all the addresses we have so far.
//
while (dwListenCount > 0) { dwListenCount--; ppAddress--; IDirectPlay8Address_Release(*ppAddress); *ppAddress = NULL; }
goto Failure; } *ppAddress++ = spInfoData.pAddress; dwListenCount++; }
pBilink = pBilink->GetNext(); }
pListenSP->Unlock(); pListenSP = NULL;
pBilinkSP = pBilinkSP->GetNext(); } pListenParent->Unlock();
*pcAddress = dwListenCount;
hResultCode = DPN_OK;
pListenParent->Release(); pListenParent = NULL;
Exit: DPF_RETURN(hResultCode);
Failure: if (pListenParent) { pListenParent->Release(); pListenParent = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
//
// DN_GetHostAddress
//
// We will determine the host addresses by examining the LISTENs which are running.
// We do this because after Host migration, we may not be running the same LISTEN
// we started with.
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetHostAddress"
STDMETHODIMP DN_GetHostAddress(PVOID pInterface, IDirectPlay8Address **const prgpAddress, DWORD *const pcAddress, const DWORD dwFlags) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject;
DPFX(DPFPREP, 3,"Parameters: pInterface [0x%p], prgpAddress [0x%p], pcAddress [0x%p], dwFlags [0x%lx]", pInterface,prgpAddress,pcAddress,dwFlags);
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION ) { if( FAILED( hResultCode = DN_ValidateGetHostAddress( pInterface, prgpAddress, pcAddress, dwFlags ) ) ) { DPFERR( "Error validating gethostaddress params" ); DPF_RETURN( hResultCode ); } } #endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DPFERR( "Object is not initialized" ); DPF_RETURN(DPNERR_UNINITIALIZED); }
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING ) { DPFERR("Object is connecting / starting to host" ); DPF_RETURN(DPNERR_CONNECTING); }
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) ) { DPFERR("You must be connected / hosting to get host address" ); DPF_RETURN(DPNERR_NOCONNECTION); }
pdnObject = static_cast<DIRECTNETOBJECT*>(GET_OBJECT_FROM_INTERFACE(pInterface)); DNASSERT(pdnObject != NULL);
// Actually do the work and get the addresses
hResultCode = DNGetHostAddressHelper( pdnObject, prgpAddress, pcAddress );
DPF_RETURN(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "DNUpdateListens"
HRESULT DNUpdateListens(DIRECTNETOBJECT *const pdnObject, const DWORD dwFlags) { HRESULT hResultCode; CAsyncOp *pListenParent;
DPFX(DPFPREP, 6,"Parameters: dwFlags [0x%u]", dwFlags);
DNASSERT( pdnObject != NULL ); DNASSERT( dwFlags != 0 ); DNASSERT( ! ((dwFlags & DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS) && (dwFlags & DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS)) ); hResultCode = DPNERR_GENERIC; pListenParent = NULL;
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pListenParent) { pdnObject->pListenParent->AddRef(); pListenParent = pdnObject->pListenParent; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pListenParent) { CBilink *pBilinkSP; CBilink *pBilink; CAsyncOp *pListenSP; CAsyncOp *pAsyncOp; CAsyncOp **ListenList; DWORD dwCount; DWORD dwActual;
dwCount = 0; dwActual = 0; ListenList = NULL;
pListenParent->Lock();
pBilinkSP = pListenParent->m_bilinkParent.GetNext(); while (pBilinkSP != &pListenParent->m_bilinkParent) { pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren); pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext(); while (pBilink != &pListenSP->m_bilinkParent) { dwCount++; pBilink = pBilink->GetNext(); } pListenSP->Unlock();
pBilinkSP = pBilinkSP->GetNext(); }
if (dwCount > 0) { if ((ListenList = static_cast<CAsyncOp**>(DNMalloc(dwCount*sizeof(CAsyncOp*)))) != NULL) { pBilinkSP = pListenParent->m_bilinkParent.GetNext(); while (pBilinkSP != &pListenParent->m_bilinkParent) { pListenSP = CONTAINING_OBJECT(pBilinkSP,CAsyncOp,m_bilinkChildren); pListenSP->Lock();
pBilink = pListenSP->m_bilinkParent.GetNext(); while (pBilink != &pListenSP->m_bilinkParent) { pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren); pAsyncOp->AddRef(); ListenList[dwActual] = pAsyncOp;
dwActual++; if (dwActual > dwCount) { DNASSERT(FALSE); break; } pBilink = pBilink->GetNext(); } pListenSP->Unlock(); pBilinkSP = pBilinkSP->GetNext(); } } }
pListenParent->Unlock();
if ((ListenList != NULL) && (dwActual > 0)) { DWORD dw; DWORD dwUpdateFlags; HRESULT hrRegister;
dwUpdateFlags = 0; hrRegister = DPNERR_DPNSVRNOTAVAILABLE; if (dwFlags & DN_UPDATE_LISTEN_FLAG_HOST_MIGRATE) { dwUpdateFlags |= DN_UPDATELISTEN_HOSTMIGRATE; } if (dwFlags & DN_UPDATE_LISTEN_FLAG_ALLOW_ENUMS) { dwUpdateFlags |= DN_UPDATELISTEN_ALLOWENUMS; } if (dwFlags & DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS) { dwUpdateFlags |= DN_UPDATELISTEN_DISALLOWENUMS; }
for (dw = 0 ; dw < dwActual ; dw++) { if ((ListenList[dw]->GetResult() == DPN_OK) && (ListenList[dw]->GetProtocolHandle() != 0)) { if (dwUpdateFlags) { if (DNPUpdateListen(pdnObject->pdnProtocolData, ListenList[dw]->GetProtocolHandle(), dwUpdateFlags) == DPN_OK) { hResultCode = DPN_OK; } } #ifndef DPNBUILD_SINGLEPROCESS
if (dwFlags & DN_UPDATE_LISTEN_FLAG_DPNSVR) { if (DNRegisterListenWithDPNSVR(pdnObject,ListenList[dw]) == DPN_OK) { hrRegister = DPN_OK; } } #endif // ! DPNBUILD_SINGLEPROCESS
}
ListenList[dw]->Release(); ListenList[dw] = NULL; }
if ((dwActual != 0) && (dwFlags & DN_UPDATE_LISTEN_FLAG_DPNSVR)) { hResultCode = hrRegister; } DNFree(ListenList); ListenList = NULL; }
pListenParent->Release(); pListenParent = NULL; }
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
#ifndef DPNBUILD_SINGLEPROCESS
#undef DPF_MODNAME
#define DPF_MODNAME "DNRegisterListenWithDPNSVR"
HRESULT DNRegisterListenWithDPNSVR(DIRECTNETOBJECT *const pdnObject, CAsyncOp *const pListen) { HRESULT hResultCode; SPGETADDRESSINFODATA spInfo; CAsyncOp *pListenSP; CServiceProvider *pSP;
DPFX(DPFPREP, 6,"Parameters: pListen [0x%p]",pListen);
pListenSP = NULL; pSP = NULL;
pListen->Lock(); if (pListen->GetParent() == NULL) { pListen->Unlock(); DPFX(DPFPREP, 7,"No SP parent for listen async op"); hResultCode = DPNERR_DOESNOTEXIST; goto Failure; } pListen->GetParent()->AddRef(); pListenSP = pListen->GetParent(); pListen->Unlock(); pListenSP->Lock(); if (pListenSP->GetSP() == NULL) { pListenSP->Unlock(); DPFX(DPFPREP, 7,"No SP for listen SP async op"); hResultCode = DPNERR_DOESNOTEXIST; goto Failure; } pListenSP->GetSP()->AddRef(); pSP = pListenSP->GetSP(); pListenSP->Unlock();
pListenSP->Release(); pListenSP = NULL;
//
// Determine the address we're actually listening on
//
memset(&spInfo,0x00,sizeof(SPGETADDRESSINFODATA)); spInfo.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData, pListen->GetProtocolHandle(),&spInfo)) == DPN_OK) { DPN_SP_CAPS dnSPCaps;
#ifdef DBG
TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG
DNASSERT(spInfo.pAddress != NULL);
#ifdef DBG
DP8ASize = 512; IDirectPlay8Address_GetURL(spInfo.pAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 7,"Listen address [%s]",DP8ABuffer); #endif // DBG
//
// Determine if the listen's SP supports DPNSVR
//
if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) == DPN_OK) { if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSDPNSRV) { DWORD dwRetry;
//
// We re-try the registration to catch the case where DPNSVR is shutting
// down while we are trying to register. Unlikely but has to be handled.
//
for( dwRetry = 0; dwRetry < DPNSVR_REGISTER_ATTEMPTS ; dwRetry ++ ) { hResultCode = pdnObject->ApplicationDesc.RegisterWithDPNSVR( spInfo.pAddress ); if (hResultCode == DPN_OK || hResultCode == DPNERR_ALREADYREGISTERED) { //
// Flag registering with DPNSVR for cleanup
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags |= DN_OBJECT_FLAG_DPNSVR_REGISTERED; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); hResultCode = DPN_OK; break; } else { if( dwRetry < DPNSVR_REGISTER_ATTEMPTS ) { DPFX(DPFPREP, 0, "Unable to register ourselves with DPNSVR hr=0x%x, retrying", hResultCode ); Sleep( DPNSVR_REGISTER_SLEEP ); } else { DPFX(DPFPREP, 0, "Unable to register ourselves with DPNSVR hr=0x%x", hResultCode ); } } } } }
IDirectPlay8Address_Release(spInfo.pAddress); spInfo.pAddress = NULL; }
pSP->Release(); pSP = NULL;
Exit: DNASSERT( pListenSP == NULL ); DNASSERT( pSP == NULL );
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pListenSP) { pListenSP->Release(); pListenSP = NULL; } if (pSP) { pSP->Release(); pSP = NULL; } goto Exit; }
#endif // ! DPNBUILD_SINGLEPROCESS
#undef DPF_MODNAME
#define DPF_MODNAME "DNAddRefLock"
HRESULT DNAddRefLock(DIRECTNETOBJECT *const pdnObject) { DNEnterCriticalSection(&pdnObject->csDirectNetObject); if ((pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) || !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED)) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); return(DPNERR_ALREADYCLOSING); } pdnObject->dwLockCount++; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
return(DPN_OK); }
#undef DPF_MODNAME
#define DPF_MODNAME "DNDecRefLock"
void DNDecRefLock(DIRECTNETOBJECT *const pdnObject) { BOOL fSetEvent;
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwLockCount--; if ((pdnObject->dwLockCount == 0) && (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)) { fSetEvent = TRUE; } else { fSetEvent = FALSE; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (fSetEvent) { DNSetEvent(pdnObject->hLockEvent); } }
#ifndef DPNBUILD_NONSEQUENTIALWORKERQUEUE
#undef DPF_MODNAME
#define DPF_MODNAME "DNThreadPoolAddRef"
void DNThreadPoolAddRef(DIRECTNETOBJECT *const pdnObject) { LONG lRefCount;
DNASSERT(pdnObject->lThreadPoolRefCount >= 0); lRefCount = DNInterlockedIncrement( (LONG*)&pdnObject->lThreadPoolRefCount ); DPFX(DPFPREP, 9, "Thread pool refcount = %i", lRefCount); }
#undef DPF_MODNAME
#define DPF_MODNAME "DNThreadPoolRelease"
void DNThreadPoolRelease(DIRECTNETOBJECT *const pdnObject) { LONG lRefCount;
DNASSERT(pdnObject->lThreadPoolRefCount > 0); lRefCount = DNInterlockedDecrement( (LONG*)&pdnObject->lThreadPoolRefCount );
if (lRefCount == 0) { DPFX(DPFPREP, 9, "Thread pool refcount = 0, setting shut down event"); DNASSERT( pdnObject->ThreadPoolShutDownEvent ); pdnObject->ThreadPoolShutDownEvent->Set(); } else { DPFX(DPFPREP, 9, "Thread pool refcount = %i", lRefCount); } } #endif // DPNBUILD_NONSEQUENTIALWORKERQUEUE
|