|
|
/*==========================================================================
* * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved. * * File: Request.cpp * Content: Requested operations *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 03/18/00 mjn Created * 04/16/00 mjn DNSendMessage uses CAsyncOp * 04/19/00 mjn Update NameTable operations to use DN_WORKER_JOB_SEND_NAMETABLE_OPERATION * 04/24/00 mjn Updated Group and Info operations to use CAsyncOp's * 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer() * 05/16/00 mjn Better locking during User notifications * 05/31/00 mjn Added operation specific SYNC flags * 06/26/00 mjn Replaced DPNADDCLIENTTOGROUP_SYNC DPNADDPLAYERTOGROUP_SYNC * mjn Replaced DPNREMOVECLIENTFROMGROUP_SYNC with DPNREMOVEPLAYERFROMGROUP_SYNC * 07/26/00 mjn Fixed locking problem with CAsyncOp::MakeChild() * 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 Added DNProcessFailedRequest() * 08/06/00 mjn Added CWorkerJob * 08/07/00 mjn Added DNRequestIntegrityCheck(),DNHostCheckIntegrity(),DNProcessCheckIntegrity(),DNHostFixIntegrity() * 08/08/00 mjn Mark groups created after CREATE_GROUP * 08/09/00 mjn Made requests and host operations more robust for host migration * 08/15/00 mjn Keep request operations if HostPlayer or connection is unavailable * 09/05/00 mjn Removed dwIndex from CNameTable::InsertEntry() * 09/13/00 mjn Perform queued operations after creating group in DNConnectToHost2() * 09/26/00 mjn Removed locking from CNameTable::SetVersion() and CNameTable::GetNewVersion() * 10/10/00 mjn Return DPN_OK from Host operations if unable to get reference on local player * 10/13/00 mjn Update version if FindPlayer fails in DNProcessXXX() functions * 01/09/01 mjn Prevent asynchronous group/info operations from being cancelled * 01/25/01 mjn Fixed 64-bit alignment problem in received messages * 04/13/01 mjn Remove requests from request list when operations received from host * 07/24/01 mjn Added DPNBUILD_NOSERVER compile flag *@@END_MSINTERNAL * ***************************************************************************/
#include "dncorei.h"
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
#undef DPF_MODNAME
#define DPF_MODNAME "DNRequestWorker"
HRESULT DNRequestWorker(DIRECTNETOBJECT *const pdnObject, DWORD dwMsgId, CRefCountBuffer* pRefCountBuffer, void *const pvRequestContext, void *const pvUserContext, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; CAsyncOp *pRequest; CAsyncOp *pHandleParent; CSyncEvent *pSyncEvent; CNameTableEntry *pHostPlayer; CConnection *pConnection; HRESULT volatile hrOperation;
pRequest = NULL; pHandleParent = NULL; pSyncEvent = NULL; pHostPlayer = NULL; pConnection = NULL;
//
// Create synchronization event if necessary
//
DBG_CASSERT(DPNOP_SYNC == DPNCREATEGROUP_SYNC); DBG_CASSERT(DPNOP_SYNC == DPNDESTROYGROUP_SYNC); DBG_CASSERT(DPNOP_SYNC == DPNADDPLAYERTOGROUP_SYNC); DBG_CASSERT(DPNOP_SYNC == DPNREMOVEPLAYERFROMGROUP_SYNC); DBG_CASSERT(DPNOP_SYNC == DPNSETGROUPINFO_SYNC); DBG_CASSERT(DPNOP_SYNC == DPNSETCLIENTINFO_SYNC); DBG_CASSERT(DPNOP_SYNC == DPNSETSERVERINFO_SYNC); DBG_CASSERT(DPNOP_SYNC == DPNSETPEERINFO_SYNC); if (dwFlags & DPNOP_SYNC) { if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK) { DPFERR("Could not create synchronization event"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } } else { if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create user HANDLE"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } }
//
// Get host connection for request operation.
// We will procede even if we can't get it, just so that the operation will be re-tried at host migration
// or cancelled at close
//
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) == DPN_OK) { if ((hResultCode = pHostPlayer->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get host connection reference"); DisplayDNError(0,hResultCode); } pHostPlayer->Release(); pHostPlayer = NULL; } else { DPFERR("Could not find Host player"); DisplayDNError(0,hResultCode); }
//
// Send request
//
hResultCode = DNPerformRequest( pdnObject, dwMsgId, pRefCountBuffer->BufferDescAddress(), pConnection, pHandleParent, &pRequest );
if (pConnection) { pConnection->Release(); pConnection = NULL; }
//
// Wait for SyncEvent or create async user HANDLE
//
pRequest->SetContext( pvRequestContext ); if (dwFlags & DPNOP_SYNC) { pRequest->SetSyncEvent( pSyncEvent ); pRequest->SetResultPointer( &hrOperation ); pRequest->Release(); pRequest = NULL;
pSyncEvent->WaitForEvent(); pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL;
hResultCode = hrOperation; } else { pRequest->Release(); pRequest = NULL;
if (phAsyncOp) { *phAsyncOp = pHandleParent->GetHandle(); } pHandleParent->SetCompletion( DNCompleteAsyncHandle ); pHandleParent->SetContext( pvUserContext ); pHandleParent->SetCannotCancel(); pHandleParent->Release(); pHandleParent = NULL;
hResultCode = DPNERR_PENDING; }
Exit: return(hResultCode);
Failure: if (pHostPlayer) { pHostPlayer->Release(); pHostPlayer = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pRequest) { pRequest->Release(); pRequest = NULL; } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pSyncEvent) { pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNRequestCreateGroup"
HRESULT DNRequestCreateGroup(DIRECTNETOBJECT *const pdnObject, const PWSTR pwszName, const DWORD dwNameSize, const PVOID pvData, const DWORD dwDataSize, const DWORD dwGroupFlags, void *const pvGroupContext, void *const pvUserContext, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CPackedBuffer packedBuffer; DN_INTERNAL_MESSAGE_REQ_CREATE_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: pwszName [%ls], pvData [0x%p], dwDataSize [%ld], dwGroupFlags [0x%lx], pvUserContext [0x%p], dwFlags [0x%lx]", pwszName,pvData,dwDataSize,dwGroupFlags,pvUserContext,dwFlags);
DNASSERT(pdnObject != NULL);
pRefCountBuffer = NULL;
//
// Create REQUEST
//
// Create buffer
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_REQ_CREATE_GROUP) + dwNameSize + dwDataSize, MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not create new RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); pMsg = static_cast<DN_INTERNAL_MESSAGE_REQ_CREATE_GROUP*>(packedBuffer.GetHeadAddress()); if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_REQ_CREATE_GROUP))) != DPN_OK) { DPFERR("Could not reserve space at front of buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// Flags
pMsg->dwGroupFlags = dwGroupFlags; pMsg->dwInfoFlags = 0;
// Add Name
if (dwNameSize) { if ((hResultCode = packedBuffer.AddToBack(pwszName,dwNameSize)) != DPN_OK) { DPFERR("Could not add Name to packed buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dwNameOffset = packedBuffer.GetTailOffset(); pMsg->dwNameSize = dwNameSize; pMsg->dwInfoFlags |= DPNINFO_NAME; } else { pMsg->dwNameOffset = 0; pMsg->dwNameSize = 0; }
// Add Data
if (dwDataSize) { if ((hResultCode = packedBuffer.AddToBack(pvData,dwDataSize)) != DPN_OK) { DPFERR("Could not add Data to packed buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dwDataOffset = packedBuffer.GetTailOffset(); pMsg->dwDataSize = dwDataSize; pMsg->dwInfoFlags |= DPNINFO_DATA; } else { pMsg->dwDataOffset = 0; pMsg->dwDataSize = 0; }
// Test against FAILED so DPNSUCCESS_PENDING doesn't show up as a failure
if (FAILED(hResultCode = DNRequestWorker(pdnObject, DN_MSG_INTERNAL_REQ_CREATE_GROUP, pRefCountBuffer, pvGroupContext, pvUserContext, phAsyncOp, dwFlags))) { DPFERR("Could not perform request"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
Exit: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNRequestDestroyGroup"
HRESULT DNRequestDestroyGroup(DIRECTNETOBJECT *const pdnObject, const DPNID dpnidGroup, PVOID const pvUserContext, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; DN_INTERNAL_MESSAGE_REQ_DESTROY_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnidGroup [0x%lx], pvUserContext [0x%p], phAsyncOp [0x%p], dwFlags [0x%lx]", dpnidGroup,pvUserContext,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL); DNASSERT(dpnidGroup != 0);
pRefCountBuffer = NULL;
//
// Create REQUEST
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_REQ_DESTROY_GROUP), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not allocate count buffer (request destroy group)"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_DESTROY_GROUP*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidGroup = dpnidGroup;
// Test against FAILED so DPNSUCCESS_PENDING doesn't show up as a failure
if (FAILED(hResultCode = DNRequestWorker(pdnObject, DN_MSG_INTERNAL_REQ_DESTROY_GROUP, pRefCountBuffer, NULL, pvUserContext, phAsyncOp, dwFlags))) { DPFERR("Could not perform request"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
Exit: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNRequestAddPlayerToGroup"
HRESULT DNRequestAddPlayerToGroup(DIRECTNETOBJECT *const pdnObject, const DPNID dpnidGroup, const DPNID dpnidPlayer, PVOID const pvUserContext, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CPackedBuffer packedBuffer; DN_INTERNAL_MESSAGE_REQ_ADD_PLAYER_TO_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnidGroup [0x%lx], dpnidPlayer [0x%lx], pvUserContext [0x%p], phAsyncOp [0x%p], dwFlags [0x%lx]", dpnidGroup,dpnidPlayer,pvUserContext,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL); DNASSERT(dpnidGroup != 0);
pRefCountBuffer = NULL;
//
// Create REQUEST
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_REQ_ADD_PLAYER_TO_GROUP), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not allocate count buffer (request destroy group)"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_ADD_PLAYER_TO_GROUP*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidGroup = dpnidGroup; pMsg->dpnidPlayer = dpnidPlayer;
// Test against FAILED so DPNSUCCESS_PENDING doesn't show up as a failure
if (FAILED(hResultCode = DNRequestWorker(pdnObject, DN_MSG_INTERNAL_REQ_ADD_PLAYER_TO_GROUP, pRefCountBuffer, NULL, pvUserContext, phAsyncOp, dwFlags))) { DPFERR("Could not perform request"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
Exit: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNRequestDeletePlayerFromGroup"
HRESULT DNRequestDeletePlayerFromGroup(DIRECTNETOBJECT *const pdnObject, const DPNID dpnidGroup, const DPNID dpnidPlayer, PVOID const pvUserContext, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CPackedBuffer packedBuffer; DN_INTERNAL_MESSAGE_REQ_DELETE_PLAYER_FROM_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnidGroup [0x%lx], dpnidPlayer [0x%lx], pvUserContext [0x%p], phAsyncOp [0x%p], dwFlags [0x%lx]", dpnidGroup,dpnidPlayer,pvUserContext,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL); DNASSERT(dpnidGroup != 0);
pRefCountBuffer = NULL;
//
// Create REQUEST
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_REQ_DELETE_PLAYER_FROM_GROUP), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not allocate count buffer (request destroy group)"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_DELETE_PLAYER_FROM_GROUP*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidGroup = dpnidGroup; pMsg->dpnidPlayer = dpnidPlayer;
// Test against FAILED so DPNSUCCESS_PENDING doesn't show up as a failure
if (FAILED(hResultCode = DNRequestWorker(pdnObject, DN_MSG_INTERNAL_REQ_DELETE_PLAYER_FROM_GROUP, pRefCountBuffer, NULL, pvUserContext, phAsyncOp, dwFlags))) { DPFERR("Could not perform request"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
Exit: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNRequestUpdateInfo"
HRESULT DNRequestUpdateInfo(DIRECTNETOBJECT *const pdnObject, const DPNID dpnid, const PWSTR pwszName, const DWORD dwNameSize, const PVOID pvData, const DWORD dwDataSize, const DWORD dwInfoFlags, PVOID const pvUserContext, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CPackedBuffer packedBuffer; DN_INTERNAL_MESSAGE_REQ_UPDATE_INFO *pMsg;
DPFX(DPFPREP, 4,"Parameters: pwszName [0x%p], pvData [0x%p], dwInfoFlags [%ld], dwGroupFlags [0x%lx], pvUserContext [0x%p], dwFlags [0x%lx]", pwszName,pvData,dwDataSize,dwInfoFlags,pvUserContext,dwFlags);
DNASSERT(pdnObject != NULL);
pRefCountBuffer = NULL;
//
// Create REQUEST
//
// Create buffer
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_REQ_UPDATE_INFO) + dwNameSize + dwDataSize, MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not create new RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); pMsg = static_cast<DN_INTERNAL_MESSAGE_REQ_UPDATE_INFO*>(packedBuffer.GetHeadAddress()); if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_REQ_UPDATE_INFO))) != DPN_OK) { DPFERR("Could not reserve space at front of buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// Add Name
if ((dwInfoFlags & DPNINFO_NAME) && dwNameSize) { if ((hResultCode = packedBuffer.AddToBack(pwszName,dwNameSize)) != DPN_OK) { DPFERR("Could not add Name to packed buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dwNameOffset = packedBuffer.GetTailOffset(); pMsg->dwNameSize = dwNameSize; } else { pMsg->dwNameOffset = 0; pMsg->dwNameSize = 0; }
// Add Data
if ((dwInfoFlags & DPNINFO_DATA) && dwDataSize) { if ((hResultCode = packedBuffer.AddToBack(pvData,dwDataSize)) != DPN_OK) { DPFERR("Could not add Data to packed buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dwDataOffset = packedBuffer.GetTailOffset(); pMsg->dwDataSize = dwDataSize; } else { pMsg->dwDataOffset = 0; pMsg->dwDataSize = 0; }
// Remaining fields
pMsg->dpnid = dpnid; pMsg->dwInfoFlags = dwInfoFlags;
// Test against FAILED so DPNSUCCESS_PENDING doesn't show up as a failure
if (FAILED(hResultCode = DNRequestWorker(pdnObject, DN_MSG_INTERNAL_REQ_UPDATE_INFO, pRefCountBuffer, NULL, pvUserContext, phAsyncOp, dwFlags))) { DPFERR("Could not perform request"); DisplayDNError(0,hResultCode); goto Failure; }
Exit: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: goto Exit; }
// DNRequestIntegrityCheck
//
// In the case where a non-host player detects a disconnect from another non-host player,
// the detecting player will request the host to perform an integrity check to prevent a
// disjoint game from occurring. The host will ping the disconnected player, and if a
// response is received, the host will disconnect the detecting player. If no response
// is received, presumably the disconnected player is in fact dropping, and a DESTROY_PLAYER
// message will be sent out.
#undef DPF_MODNAME
#define DPF_MODNAME "DNRequestIntegrityCheck"
HRESULT DNRequestIntegrityCheck(DIRECTNETOBJECT *const pdnObject, const DPNID dpnidTarget) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CNameTableEntry *pHostPlayer; CNameTableEntry *pNTEntry; CConnection *pConnection; CAsyncOp *pRequest; DN_INTERNAL_MESSAGE_REQ_INTEGRITY_CHECK *pMsg;
DPFX(DPFPREP, 6,"Parameters: dpnidTarget [0x%lx]",dpnidTarget);
pRefCountBuffer = NULL; pHostPlayer = NULL; pNTEntry = NULL; pConnection = NULL; pRequest = NULL;
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); DPFERR("Closing - aborting"); hResultCode = DPN_OK; goto Failure; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Determine if player is still in NameTable - maybe the Host has already deleted him
//
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidTarget,&pNTEntry)) != DPN_OK) { DPFERR("Target player not in NameTable"); DisplayDNError(0,hResultCode); hResultCode = DPN_OK; goto Failure; } pNTEntry->Lock(); if (!pNTEntry->IsAvailable()) { pNTEntry->Unlock(); hResultCode = DPN_OK; goto Failure; } pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL;
//
// Create request message
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_REQ_INTEGRITY_CHECK), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_INTEGRITY_CHECK*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidTarget = dpnidTarget;
//
// Get host connection for request operation
//
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) != DPN_OK) { DPFERR("Could not get host player reference"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = pHostPlayer->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get host connection reference"); DisplayDNError(0,hResultCode); goto Failure; } pHostPlayer->Release(); pHostPlayer = NULL;
//
// Send request
//
if ((hResultCode = DNPerformRequest(pdnObject, DN_MSG_INTERNAL_REQ_INTEGRITY_CHECK, pRefCountBuffer->BufferDescAddress(), pConnection, NULL, &pRequest)) != DPNERR_PENDING) { DPFERR("Could not perform request (INTEGRITY_CHECK)"); DisplayDNError(0,hResultCode); goto Failure; } pConnection->Release(); pConnection = NULL; pRefCountBuffer->Release(); pRefCountBuffer = NULL;
pRequest->Release(); pRequest = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pHostPlayer) { pHostPlayer->Release(); pHostPlayer = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pRequest) { pRequest->Release(); pRequest = NULL; } goto Exit; }
// HOST OPERATIONS
//
// The Host will perform an operation and if in PEER mode, will inform
// other players of the operation. These messages will contain the
// DPNID of the player requesting the operation along with the HANDLE
// supplied with the request.
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostProcessRequest"
HRESULT DNHostProcessRequest(DIRECTNETOBJECT *const pdnObject, const DWORD dwMsgId, PVOID const pv, const DPNID dpnidRequesting) { HRESULT hResultCode; UNALIGNED DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION *pRequest;
DPFX(DPFPREP, 6,"Parameters: dwMsgId [0x%lx], pv [0x%p], dpnidRequesting [0x%lx]", dwMsgId,pv,dpnidRequesting);
DNASSERT(pdnObject != NULL); DNASSERT(pv != NULL); DNASSERT(dpnidRequesting != 0);
pRequest = static_cast<DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION*>(pv);
switch(dwMsgId) { case DN_MSG_INTERNAL_REQ_CREATE_GROUP: { UNALIGNED DN_INTERNAL_MESSAGE_REQ_CREATE_GROUP *pCreateGroup; PWSTR pwszName; PVOID pvData;
DPFX(DPFPREP, 7,"DN_MSG_INTERNAL_REQ_CREATE_GROUP");
pCreateGroup = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_CREATE_GROUP*>(pRequest + 1); if (pCreateGroup->dwNameSize) { pwszName = reinterpret_cast<WCHAR*>(reinterpret_cast<BYTE*>(pCreateGroup) + pCreateGroup->dwNameOffset); } else { pwszName = NULL; } if (pCreateGroup->dwDataSize) { pvData = static_cast<void*>(reinterpret_cast<BYTE*>(pCreateGroup) + pCreateGroup->dwDataOffset); } else { pvData = NULL; } DNHostCreateGroup( pdnObject, pwszName, pCreateGroup->dwNameSize, pvData, pCreateGroup->dwDataSize, pCreateGroup->dwInfoFlags, pCreateGroup->dwGroupFlags, NULL, NULL, dpnidRequesting, pRequest->hCompletionOp, NULL, 0 );
break; }
case DN_MSG_INTERNAL_REQ_DESTROY_GROUP: { UNALIGNED DN_INTERNAL_MESSAGE_REQ_DESTROY_GROUP *pDestroyGroup;
DPFX(DPFPREP, 7,"DN_MSG_INTERNAL_REQ_DESTROY_GROUP");
pDestroyGroup = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_DESTROY_GROUP*>(pRequest + 1);
DNHostDestroyGroup( pdnObject, pDestroyGroup->dpnidGroup, NULL, dpnidRequesting, pRequest->hCompletionOp, NULL, 0 ); break; }
case DN_MSG_INTERNAL_REQ_ADD_PLAYER_TO_GROUP: { UNALIGNED DN_INTERNAL_MESSAGE_REQ_ADD_PLAYER_TO_GROUP *pAddPlayerToGroup;
DPFX(DPFPREP, 7,"DN_MSG_INTERNAL_REQ_ADD_PLAYER_TO_GROUP");
pAddPlayerToGroup = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_ADD_PLAYER_TO_GROUP*>(pRequest + 1);
DNHostAddPlayerToGroup( pdnObject, pAddPlayerToGroup->dpnidGroup, pAddPlayerToGroup->dpnidPlayer, NULL, dpnidRequesting, pRequest->hCompletionOp, NULL, 0 );
break; }
case DN_MSG_INTERNAL_REQ_DELETE_PLAYER_FROM_GROUP: { UNALIGNED DN_INTERNAL_MESSAGE_REQ_DELETE_PLAYER_FROM_GROUP *pDeletePlayerFromGroup;
DPFX(DPFPREP, 7,"DN_MSG_INTERNAL_REQ_DELETE_PLAYER_FROM_GROUP");
pDeletePlayerFromGroup = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_DELETE_PLAYER_FROM_GROUP*>(pRequest + 1);
DNHostDeletePlayerFromGroup(pdnObject, pDeletePlayerFromGroup->dpnidGroup, pDeletePlayerFromGroup->dpnidPlayer, NULL, dpnidRequesting, pRequest->hCompletionOp, NULL, 0);
break; }
case DN_MSG_INTERNAL_REQ_UPDATE_INFO: { UNALIGNED DN_INTERNAL_MESSAGE_REQ_UPDATE_INFO *pUpdateInfo; PWSTR pwszName; PVOID pvData;
DPFX(DPFPREP, 7,"DN_MSG_INTERNAL_REQ_UPDATE_INFO");
pUpdateInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_UPDATE_INFO*>(pRequest + 1); if (pUpdateInfo->dwNameSize) { pwszName = reinterpret_cast<WCHAR*>(reinterpret_cast<BYTE*>(pUpdateInfo) + pUpdateInfo->dwNameOffset); } else { pwszName = NULL; } if (pUpdateInfo->dwDataSize) { pvData = reinterpret_cast<void*>(reinterpret_cast<BYTE*>(pUpdateInfo) + pUpdateInfo->dwDataOffset); } else { pvData = NULL; } DNHostUpdateInfo(pdnObject, pUpdateInfo->dpnid, pwszName, pUpdateInfo->dwNameSize, pvData, pUpdateInfo->dwDataSize, pUpdateInfo->dwInfoFlags, NULL, dpnidRequesting, pRequest->hCompletionOp, NULL, 0);
break; }
case DN_MSG_INTERNAL_REQ_INTEGRITY_CHECK: { UNALIGNED DN_INTERNAL_MESSAGE_REQ_INTEGRITY_CHECK *pIntegrityCheck; CNameTableEntry *pLocalPlayer;
DPFX(DPFPREP, 7,"DN_MSG_INTERNAL_REQ_INTEGRITY_CHECK");
pIntegrityCheck = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_INTEGRITY_CHECK*>(pRequest + 1);
//
// If we submitted this request, this is being called during host migration,
// so remove it from the handle table since we will destroy the dropped player anyways.
// Otherwise, we will perform the integrity check
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) == DPN_OK) { if (pLocalPlayer->GetDPNID() == dpnidRequesting) { CAsyncOp* pAsyncOp; if (SUCCEEDED(pdnObject->HandleTable.Destroy( pRequest->hCompletionOp, (PVOID*)&pAsyncOp ))) { // Release the HandleTable reference
pAsyncOp->Release(); } } else { DNHostCheckIntegrity(pdnObject,pIntegrityCheck->dpnidTarget,dpnidRequesting); } pLocalPlayer->Release(); pLocalPlayer = NULL; } break; }
default: { DPFERR("How did we get here ?"); DNASSERT(FALSE); } }
DPFX(DPFPREP, 6,"Returning: DPN_OK"); return(DPN_OK); }
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostFailRequest"
void DNHostFailRequest(DIRECTNETOBJECT *const pdnObject, const DPNID dpnid, const DPNHANDLE hCompletionOp, const HRESULT hr) { HRESULT hResultCode; CNameTableEntry *pNTEntry; CRefCountBuffer *pRefCountBuffer; CConnection *pConnection; DN_INTERNAL_MESSAGE_REQUEST_FAILED *pMsg;
DNASSERT(pdnObject != NULL); DNASSERT(dpnid != NULL);
pNTEntry = NULL; pRefCountBuffer = NULL; pConnection = NULL;
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find NameTableEntry"); DisplayDNError(0,hResultCode); goto Failure; }
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_REQUEST_FAILED), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not create new RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_REQUEST_FAILED*>(pRefCountBuffer->GetBufferAddress()); pMsg->hCompletionOp = hCompletionOp; pMsg->hResultCode = hr;
if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) == DPN_OK) { hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_REQUEST_FAILED, dpnid, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL);
pConnection->Release(); pConnection = NULL; }
pNTEntry->Release(); pNTEntry = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL;
Exit: return;
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostCreateGroup"
HRESULT DNHostCreateGroup(DIRECTNETOBJECT *const pdnObject, PWSTR pwszName, const DWORD dwNameSize, void *const pvData, const DWORD dwDataSize, const DWORD dwInfoFlags, const DWORD dwGroupFlags, void *const pvGroupContext, void *const pvUserContext, const DPNID dpnidOwner, const DPNHANDLE hCompletionOp, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; HRESULT hrOperation; void *pvContext; BOOL fHostRequested; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry; CPackedBuffer packedBuffer; CRefCountBuffer *pRefCountBuffer; CAsyncOp *pHandleParent; CAsyncOp *pRequest; CWorkerJob *pWorkerJob; DN_INTERNAL_MESSAGE_CREATE_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: pwszName [0x%p], dwNameSize [%ld], pvData [0x%p], dwDataSize [%ld], dwInfoFlags [0x%lx], dwGroupFlags [0x%lx], pvGroupContext [0x%p], pvUserContext [0x%p], dpnidOwner [0x%lx], hCompletionOp [0x%lx], phAsyncOp [0x%p], dwFlags [0x%lx]", pwszName,dwNameSize,pvData,dwDataSize,dwInfoFlags,dwGroupFlags,pvGroupContext,pvUserContext,dpnidOwner,hCompletionOp,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL);
//
// If this is called from DN_CreateGroup(),
// hCompletion=0
// dpnidOwner = DPNID of Host
// pvGroupContext is valid
// pvUserContext is valid
//
// If this is called by a REQUEST,
// hCompletion = REQUEST handle of requesting player
// dpnidOwner = DPNID of requesting player
// pvGroupContext is not valid
//
// If this is called at HostMigration,
// hCompletion = REQUEST handle on THIS (now Host) player
// dpnidOwner = DPNID of THIS (now Host) player
// pvGroupContext is invalid
// pvUserContext is invalid
//
pLocalPlayer = NULL; pNTEntry = NULL; pRefCountBuffer = NULL; pWorkerJob = NULL; pHandleParent = NULL; pRequest = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); return(DPN_OK); // Ignore and continue (!)
} if (pLocalPlayer->GetDPNID() == dpnidOwner) { fHostRequested = TRUE; } else { fHostRequested = FALSE; } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Get group context if this is a Host Migration re-try by finding REQUEST AsyncOp
//
if ((fHostRequested) && (hCompletionOp != 0)) { if ((hResultCode = pdnObject->HandleTable.Find( hCompletionOp,(PVOID*)&pRequest )) != DPN_OK) { DPFERR("Could not find REQUEST AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } else { // We would normally AddRef pRequest in the success case, but since we need to release it
// next we will eliminate both.
} pvContext = pRequest->GetContext(); // pRequest->Release(); // Don't need since we are balancing with HandleTable ref
pRequest = NULL; } else { pvContext = pvGroupContext; }
//
// Create and fill in NameTableEntry
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pNTEntry)) != DPN_OK) { DPFERR("Could not create new NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pNTEntry->MakeGroup();
// This function takes the lock internally
pNTEntry->UpdateEntryInfo(pwszName,dwNameSize,pvData,dwDataSize,dwInfoFlags, FALSE);
pNTEntry->SetOwner( dpnidOwner ); pNTEntry->SetContext( pvContext );
if (dwGroupFlags & DPNGROUP_AUTODESTRUCT) { pNTEntry->MakeAutoDestructGroup(); }
//
// Add Group to NameTable
//
#pragma TODO(minara,"Check to see if Autodestruct owner is still in NameTable")
#pragma TODO(minara,"This should happen after getting a NameTable version number - as DESTROY player will clean up")
#pragma TODO(minara,"We should send out a NOP in this case")
hrOperation = pdnObject->NameTable.AddEntry(pNTEntry); if (hrOperation != DPN_OK) { DPFERR("Could not add NameTableEntry to NameTable"); DisplayDNError(0,hResultCode); if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidOwner,hCompletionOp,hrOperation); } } else { BOOL fNotify;
fNotify = FALSE; pNTEntry->Lock(); if (!pNTEntry->IsAvailable() && !pNTEntry->IsDisconnecting()) { pNTEntry->MakeAvailable(); pNTEntry->NotifyAddRef(); pNTEntry->NotifyAddRef(); pNTEntry->SetInUse(); fNotify = TRUE; } pNTEntry->Unlock();
if (fNotify) { DNUserCreateGroup(pdnObject,pNTEntry);
pNTEntry->PerformQueuedOperations();
pdnObject->NameTable.PopulateGroup( pNTEntry ); }
//
// Send CREATE_GROUP message
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { // Determine size of message
packedBuffer.Initialize(NULL,0); packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CREATE_GROUP)); pNTEntry->PackEntryInfo(&packedBuffer);
// Create buffer
if ((hResultCode = RefCountBufferNew(pdnObject,packedBuffer.GetSizeRequired(),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); pMsg = static_cast<DN_INTERNAL_MESSAGE_CREATE_GROUP*>(packedBuffer.GetHeadAddress()); if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CREATE_GROUP))) != DPN_OK) { DPFERR("Could not reserve front of buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((hResultCode = pNTEntry->PackEntryInfo(&packedBuffer)) != DPN_OK) { DPFERR("Could not pack NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dpnidRequesting = dpnidOwner; pMsg->hCompletionOp = hCompletionOp;
//
// SEND CreateGroup messages via WorkerThread
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create new WorkerJob"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_CREATE_GROUP ); pWorkerJob->SetSendNameTableOperationVersion( pNTEntry->GetVersion() ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL; } }
pNTEntry->Release(); pNTEntry = NULL;
//
// If this was called by the local (Host) player,
// Check to see if this was an original operation or a re-try from HostMigration
//
// If this was an original operation,
// See if we need an Async HANDLE for the user
// Otherwise
// Clean up the outstanding operation
//
if (fHostRequested) { if (hCompletionOp == 0) // Original
{ //
// If this fails, or is synchronous, return the operation result immediately
//
if (!(dwFlags & DPNCREATEGROUP_SYNC) && (hrOperation == DPN_OK)) { if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create Async HANDLE"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pHandleParent->SetCompletion( DNCompleteAsyncHandle ); pHandleParent->SetContext( pvUserContext ); pHandleParent->SetResult( hrOperation ); pHandleParent->SetCannotCancel(); *phAsyncOp = pHandleParent->GetHandle(); pHandleParent->Release(); pHandleParent = NULL;
hResultCode = DPNERR_PENDING; } else { hResultCode = hrOperation; } } else // Host Migration re-try
{ if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pRequest ))) { pRequest->SetResult( hrOperation );
// Release the HandleTable reference
pRequest->Release(); } pRequest = NULL;
hResultCode = DPN_OK; } } else { hResultCode = DPN_OK; }
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidOwner,hCompletionOp,hrOperation); } else { //
// If a completion op was specified and this was requested by the Host, this is a
// retry of an operation during Host migration. In this case, we want to set the
// result (failure code) of the completion op, and remove it from the HandleTable.
//
if (hCompletionOp) { CAsyncOp *pHostCompletionOp;
pHostCompletionOp = NULL; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pHostCompletionOp ))) { pHostCompletionOp->SetResult( hResultCode );
// Release the HandleTable reference
pHostCompletionOp->Release(); } pHostCompletionOp = NULL;
DNASSERT(pHostCompletionOp == NULL); } } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pRequest) { pRequest->Release(); pRequest = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostDestroyGroup"
HRESULT DNHostDestroyGroup(DIRECTNETOBJECT *const pdnObject, const DPNID dpnid, void *const pvUserContext, const DPNID dpnidRequesting, const DPNHANDLE hCompletionOp, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; HRESULT hrOperation; DWORD dwVersion; BOOL fHostRequested; CNameTableEntry *pLocalPlayer; CRefCountBuffer *pRefCountBuffer; CAsyncOp *pHandleParent; CWorkerJob *pWorkerJob; DN_INTERNAL_MESSAGE_DESTROY_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnid [0x%lx], pvUserContext [0x%p], dpnidRequesting [0x%lx], hCompletionOp [0x%lx], phAsyncOp [0x%p], dwFlags [0x%lx]", dpnid,pvUserContext,dpnidRequesting,hCompletionOp,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL); DNASSERT(dpnid != 0); DNASSERT(dpnidRequesting != 0);
//
// If this is called from DN_DestroyGroup(),
// hCompletion=0
// dpnidRequesting = DPNID of Host
// pvUserContext is valid
//
// If this is called by a REQUEST,
// hCompletion = REQUEST handle of requesting player
// dpnidRequesting = DPNID of requesting player
// pvUserContext is not valid
//
// If this is called at HostMigration,
// hCompletion = REQUEST handle on THIS (now Host) player
// dpnidRequesting = DPNID of THIS (now Host) player
// pvUserContext is invalid
//
pLocalPlayer = NULL; pRefCountBuffer = NULL; pHandleParent = NULL; pWorkerJob = NULL;
//
// Determine if this is being requested by the Host
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); return(DPN_OK); // Ignore and continue (!)
} if (pLocalPlayer->GetDPNID() == dpnidRequesting) { fHostRequested = TRUE; } else { fHostRequested = FALSE; } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Remove Group from NameTable
//
dwVersion = 0; hrOperation = pdnObject->NameTable.DeleteGroup(dpnid,&dwVersion); if (hrOperation != DPN_OK) { DPFERR("Could not delete group from NameTable"); DisplayDNError(0,hResultCode); if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } } else { //
// Send DESTROY_GROUP message
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { // Create buffer
if ((hResultCode = RefCountBufferNew(pdnObject,sizeof(DN_INTERNAL_MESSAGE_DESTROY_GROUP),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_DESTROY_GROUP*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidGroup = dpnid; pMsg->dwVersion = dwVersion; pMsg->dwVersionNotUsed = 0; pMsg->dpnidRequesting = dpnidRequesting; pMsg->hCompletionOp = hCompletionOp;
//
// SEND DestroyGroup messages via WorkerThread
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create new WorkerJob"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_DESTROY_GROUP ); pWorkerJob->SetSendNameTableOperationVersion( dwVersion ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL; } }
//
// If this was called by the local (Host) player,
// Check to see if this was an original operation or a re-try from HostMigration
//
// If this was an original operation,
// See if we need an Async HANDLE for the user
// Otherwise
// Clean up the outstanding operation
//
if (fHostRequested) { if (hCompletionOp == 0) // Original
{ //
// If this fails, or is synchronous, return the operation result immediately
//
if (!(dwFlags & DPNDESTROYGROUP_SYNC) && (hrOperation == DPN_OK)) { if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create Async HANDLE"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pHandleParent->SetCompletion( DNCompleteAsyncHandle ); pHandleParent->SetContext( pvUserContext ); pHandleParent->SetResult( hrOperation ); pHandleParent->SetCannotCancel(); *phAsyncOp = pHandleParent->GetHandle(); pHandleParent->Release(); pHandleParent = NULL;
hResultCode = DPNERR_PENDING; } else { hResultCode = hrOperation; } } else // Host Migration re-try
{ CAsyncOp *pRequest;
pRequest = NULL;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pRequest ))) { pRequest->SetResult( hrOperation );
// Release the HandleTable reference
pRequest->Release(); } pRequest = NULL;
hResultCode = DPN_OK; } } else { hResultCode = DPN_OK; }
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } else { //
// If a completion op was specified and this was requested by the Host, this is a
// retry of an operation during Host migration. In this case, we want to set the
// result (failure code) of the completion op, and remove it from the HandleTable.
//
if (hCompletionOp) { CAsyncOp *pHostCompletionOp;
pHostCompletionOp = NULL; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pHostCompletionOp ))) { pHostCompletionOp->SetResult( hResultCode );
// Release the HandleTable reference
pHostCompletionOp->Release(); } pHostCompletionOp = NULL;
DNASSERT(pHostCompletionOp == NULL); } } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostAddPlayerToGroup"
HRESULT DNHostAddPlayerToGroup(DIRECTNETOBJECT *const pdnObject, const DPNID dpnidGroup, const DPNID dpnidPlayer, void *const pvUserContext, const DPNID dpnidRequesting, const DPNHANDLE hCompletionOp, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; HRESULT hrOperation; DWORD dwVersion; BOOL fHostRequested; CNameTableEntry *pLocalPlayer; CNameTableEntry *pPlayer; CNameTableEntry *pGroup; CRefCountBuffer *pRefCountBuffer; CAsyncOp *pHandleParent; CWorkerJob *pWorkerJob; DN_INTERNAL_MESSAGE_ADD_PLAYER_TO_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnidGroup [0x%lx], dpnidPlayer [0x%lx], pvUserContext [0x%p], dpnidRequesting [0x%lx], hCompletionOp [0x%lx], phAsyncOp [0x%p], dwFlags [0x%lx]", dpnidGroup,dpnidPlayer,pvUserContext,dpnidRequesting,hCompletionOp,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL); DNASSERT(dpnidGroup != 0); DNASSERT(dpnidPlayer != 0); DNASSERT(dpnidRequesting != 0);
//
// If this is called from DN_AddPlayerToGroup(),
// hCompletion=0
// dpnidRequesting = DPNID of Host
// pvUserContext is valid
//
// If this is called by a REQUEST,
// hCompletion = REQUEST handle of requesting player
// dpnidRequesting = DPNID of requesting player
// pvUserContext is not valid
//
// If this is called at HostMigration,
// hCompletion = REQUEST handle on THIS (now Host) player
// dpnidRequesting = DPNID of THIS (now Host) player
// pvUserContext is invalid
//
pLocalPlayer = NULL; pGroup = NULL; pPlayer = NULL; pRefCountBuffer = NULL; pHandleParent = NULL; pWorkerJob = NULL;
//
// Determine if this is being requested by the Host
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); return(DPN_OK); // Ignore and continue (!)
} if (pLocalPlayer->GetDPNID() == dpnidRequesting) { fHostRequested = TRUE; } else { fHostRequested = FALSE; } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// See if the player and group are still in the NameTable
// (this has to happen after we set fHostRequested so we can gracefully handle errors)
//
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pGroup)) != DPN_OK) { DPFERR("Could not find group"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDGROUP; hrOperation = DPNERR_INVALIDGROUP; goto Failure; } if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidPlayer,&pPlayer)) != DPN_OK) { DPFERR("Could not find player"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDPLAYER; hrOperation = DPNERR_INVALIDPLAYER; goto Failure; }
//
// Add Player To Group
//
dwVersion = 0; hrOperation = pdnObject->NameTable.AddPlayerToGroup(pGroup,pPlayer,&dwVersion);
pGroup->Release(); pGroup = NULL; pPlayer->Release(); pPlayer = NULL;
if (hrOperation != DPN_OK) { DPFERR("Could not add player to group"); DisplayDNError(0,hResultCode); if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } } else { //
// Send ADD_PLAYER_TO_GROUP message
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { // Create buffer
if ((hResultCode = RefCountBufferNew(pdnObject,sizeof(DN_INTERNAL_MESSAGE_ADD_PLAYER_TO_GROUP),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_ADD_PLAYER_TO_GROUP*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidGroup = dpnidGroup; pMsg->dpnidPlayer = dpnidPlayer; pMsg->dwVersion = dwVersion; pMsg->dwVersionNotUsed = 0; pMsg->dpnidRequesting = dpnidRequesting; pMsg->hCompletionOp = hCompletionOp;
//
// SEND AddPlayerToGroup messages via WorkerThread
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create new WorkerJob"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_ADD_PLAYER_TO_GROUP ); pWorkerJob->SetSendNameTableOperationVersion( dwVersion ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL; } }
//
// If this was called by the local (Host) player,
// Check to see if this was an original operation or a re-try from HostMigration
//
// If this was an original operation,
// See if we need an Async HANDLE for the user
// Otherwise
// Clean up the outstanding operation
//
if (fHostRequested) { if (hCompletionOp == 0) // Original
{ //
// If this fails, or is synchronous, return the operation result immediately
//
if (!(dwFlags & DPNADDPLAYERTOGROUP_SYNC) && (hrOperation == DPN_OK)) { if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create Async HANDLE"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pHandleParent->SetCompletion( DNCompleteAsyncHandle ); pHandleParent->SetContext( pvUserContext ); pHandleParent->SetResult( hrOperation ); pHandleParent->SetCannotCancel(); *phAsyncOp = pHandleParent->GetHandle(); pHandleParent->Release(); pHandleParent = NULL;
hResultCode = DPNERR_PENDING; } else { hResultCode = hrOperation; } } else // Host Migration re-try
{ CAsyncOp *pRequest;
pRequest = NULL;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pRequest ))) { pRequest->SetResult( hrOperation );
// Release the HandleTable reference
pRequest->Release(); } pRequest = NULL;
hResultCode = DPN_OK; } } else { hResultCode = DPN_OK; }
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } else { //
// If a completion op was specified and this was requested by the Host, this is a
// retry of an operation during Host migration. In this case, we want to set the
// result (failure code) of the completion op, and remove it from the HandleTable.
//
if (hCompletionOp) { CAsyncOp *pHostCompletionOp;
pHostCompletionOp = NULL; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pHostCompletionOp ))) { pHostCompletionOp->SetResult( hResultCode );
// Release the HandleTable reference
pHostCompletionOp->Release(); } pHostCompletionOp = NULL;
DNASSERT(pHostCompletionOp == NULL); } } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pGroup) { pGroup->Release(); pGroup = NULL; } if (pPlayer) { pPlayer->Release(); pPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostDeletePlayerFromGroup"
HRESULT DNHostDeletePlayerFromGroup(DIRECTNETOBJECT *const pdnObject, const DPNID dpnidGroup, const DPNID dpnidPlayer, void *const pvUserContext, const DPNID dpnidRequesting, const DPNHANDLE hCompletionOp, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; HRESULT hrOperation; DWORD dwVersion; BOOL fHostRequested; CNameTableEntry *pLocalPlayer; CNameTableEntry *pGroup; CNameTableEntry *pPlayer; CRefCountBuffer *pRefCountBuffer; CAsyncOp *pHandleParent; CWorkerJob *pWorkerJob; DN_INTERNAL_MESSAGE_DELETE_PLAYER_FROM_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnidGroup [0x%lx], dpnidPlayer [0x%lx], pvUserContext [0x%p], dpnidRequesting [0x%lx], hCompletionOp [0x%lx], phAsyncOp [0x%p], dwFlags [0x%lx]", dpnidGroup,dpnidPlayer,pvUserContext,dpnidRequesting,hCompletionOp,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL); DNASSERT(dpnidGroup != 0); DNASSERT(dpnidPlayer != 0); DNASSERT(dpnidRequesting != 0);
//
// If this is called from DN_DeletePlayerFromGroup(),
// hCompletion=0
// dpnidRequesting = DPNID of Host
// pvUserContext is valid
//
// If this is called by a REQUEST,
// hCompletion = REQUEST handle of requesting player
// dpnidRequesting = DPNID of requesting player
// pvUserContext is not valid
//
// If this is called at HostMigration,
// hCompletion = REQUEST handle on THIS (now Host) player
// dpnidRequesting = DPNID of THIS (now Host) player
// pvUserContext is invalid
//
pLocalPlayer = NULL; pGroup = NULL; pPlayer = NULL; pRefCountBuffer = NULL; pHandleParent = NULL; pWorkerJob = NULL;
//
// Determine if this is being requested by the Host
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); return(DPN_OK); // Ignore and continue (!)
}
if (pLocalPlayer->GetDPNID() == dpnidRequesting) { fHostRequested = TRUE; } else { fHostRequested = FALSE; } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// See if the player and group are still in the NameTable
// (this has to happen after we set fHostRequested so we can gracefully handle errors)
//
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidGroup,&pGroup)) != DPN_OK) { DPFERR("Could not find group"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDGROUP; hrOperation = DPNERR_INVALIDGROUP; goto Failure; } if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidPlayer,&pPlayer)) != DPN_OK) { DPFERR("Could not find player"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_INVALIDPLAYER; hrOperation = DPNERR_INVALIDPLAYER; goto Failure; }
//
// Delete Player From Group
//
dwVersion = 0; hrOperation = pdnObject->NameTable.RemovePlayerFromGroup(pGroup,pPlayer,&dwVersion); if (hrOperation != DPN_OK) { DPFERR("Could not delete player from group"); DisplayDNError(0,hrOperation); if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } } else { //
// Send DELETE_PLAYER_FROM_GROUP message if successful
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { // Create buffer
if ((hResultCode = RefCountBufferNew(pdnObject,sizeof(DN_INTERNAL_MESSAGE_DELETE_PLAYER_FROM_GROUP),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_DELETE_PLAYER_FROM_GROUP*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidGroup = dpnidGroup; pMsg->dpnidPlayer = dpnidPlayer; pMsg->dwVersion = dwVersion; pMsg->dwVersionNotUsed = 0; pMsg->dpnidRequesting = dpnidRequesting; pMsg->hCompletionOp = hCompletionOp;
//
// SEND DeletePlayerFromGroup messages via WorkerThread
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create new WorkerJob"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_DELETE_PLAYER_FROM_GROUP ); pWorkerJob->SetSendNameTableOperationVersion( dwVersion ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL; } } pGroup->Release(); pGroup = NULL; pPlayer->Release(); pPlayer = NULL;
//
// If this was called by the local (Host) player,
// Check to see if this was an original operation or a re-try from HostMigration
//
// If this was an original operation,
// See if we need an Async HANDLE for the user
// Otherwise
// Clean up the outstanding operation
//
if (fHostRequested) { if (hCompletionOp == 0) // Original
{ //
// If this fails, or is synchronous, return the operation result immediately
//
if (!(dwFlags & DPNREMOVEPLAYERFROMGROUP_SYNC) && (hrOperation == DPN_OK)) { if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create Async HANDLE"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pHandleParent->SetCompletion( DNCompleteAsyncHandle ); pHandleParent->SetContext( pvUserContext ); pHandleParent->SetResult( hrOperation ); pHandleParent->SetCannotCancel(); *phAsyncOp = pHandleParent->GetHandle(); pHandleParent->Release(); pHandleParent = NULL;
hResultCode = DPNERR_PENDING; } else { hResultCode = hrOperation; } } else // Host Migration re-try
{ CAsyncOp *pRequest;
pRequest = NULL;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pRequest ))) { pRequest->SetResult( hrOperation );
// Release the HandleTable reference
pRequest->Release(); } pRequest = NULL;
hResultCode = DPN_OK; } } else { hResultCode = DPN_OK; }
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } else { //
// If a completion op was specified and this was requested by the Host, this is a
// retry of an operation during Host migration. In this case, we want to set the
// result (failure code) of the completion op, and remove it from the HandleTable.
//
if (hCompletionOp) { CAsyncOp *pHostCompletionOp;
pHostCompletionOp = NULL; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pHostCompletionOp ))) { pHostCompletionOp->SetResult( hResultCode );
// Release the HandleTable reference
pHostCompletionOp->Release(); } pHostCompletionOp = NULL;
DNASSERT(pHostCompletionOp == NULL); } } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pGroup) { pGroup->Release(); pGroup = NULL; } if (pPlayer) { pPlayer->Release(); pPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostUpdateInfo"
HRESULT DNHostUpdateInfo(DIRECTNETOBJECT *const pdnObject, const DPNID dpnid, PWSTR pwszName, const DWORD dwNameSize, void *const pvData, const DWORD dwDataSize, const DWORD dwInfoFlags, void *const pvUserContext, const DPNID dpnidRequesting, const DPNHANDLE hCompletionOp, DPNHANDLE *const phAsyncOp, const DWORD dwFlags) { HRESULT hResultCode; HRESULT hrOperation; DWORD dwSize; DWORD dwVersion; BOOL fHostRequested; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry; CPackedBuffer packedBuffer; CRefCountBuffer *pRefCountBuffer; CAsyncOp *pHandleParent; CWorkerJob *pWorkerJob; DN_INTERNAL_MESSAGE_UPDATE_INFO *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnid [0x%lx], pwszName [0x%p], dwNameSize [%ld], pvData [0x%p], dwDataSize [%ld], dwInfoFlags [0x%lx], pvUserContext [0x%p], dpnidRequesting [0x%lx], hCompletionOp [0x%lx], phAsyncOp [0x%p], dwFlags [0x%lx]", dpnid,pwszName,dwNameSize,pvData,dwDataSize,dwInfoFlags,pvUserContext,dpnidRequesting,hCompletionOp,phAsyncOp,dwFlags);
DNASSERT(pdnObject != NULL); DNASSERT(dpnid != 0); DNASSERT(dpnidRequesting != 0);
pLocalPlayer = NULL; pNTEntry = NULL; pRefCountBuffer = NULL; pHandleParent = NULL; pWorkerJob = NULL;
//
// Determine if this is being requested by the Host
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); return(DPN_OK); // Ignore and continue (!)
} if (pLocalPlayer->GetDPNID() == dpnidRequesting) { fHostRequested = TRUE; } else { fHostRequested = FALSE; } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Update Info
//
hrOperation = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry); if (hrOperation != DPN_OK) { DPFERR("Could not find entry"); DisplayDNError(0,hResultCode); if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } } else { // This function takes the lock internally
pNTEntry->UpdateEntryInfo(pwszName,dwNameSize,pvData,dwDataSize,dwInfoFlags, (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER)) ? TRUE : !fHostRequested);
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.GetNewVersion( &dwVersion ); pdnObject->NameTable.Unlock();
//
// Send UPDATE_INFO message
//
#ifndef DPNBUILD_NOSERVER
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER | DN_OBJECT_FLAG_SERVER)) #else
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER)) #endif // DPNBUILD_NOSERVER
{ // Create buffer
dwSize = sizeof(DN_INTERNAL_MESSAGE_UPDATE_INFO) + dwNameSize + dwDataSize; if ((hResultCode = RefCountBufferNew(pdnObject,dwSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); pMsg = static_cast<DN_INTERNAL_MESSAGE_UPDATE_INFO*>(packedBuffer.GetHeadAddress()); if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_UPDATE_INFO))) != DPN_OK) { DPFERR("Could not reserve front of buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((dwInfoFlags & DPNINFO_NAME) && (pwszName) && (dwNameSize)) { if ((hResultCode = packedBuffer.AddToBack(pwszName,dwNameSize)) != DPN_OK) { DPFERR("Could not add Name to back of buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dwNameOffset = packedBuffer.GetTailOffset(); pMsg->dwNameSize = dwNameSize; } else { pMsg->dwNameOffset = 0; pMsg->dwNameSize = 0; } if ((dwInfoFlags & DPNINFO_DATA) && (pvData) && (dwDataSize)) { if ((hResultCode = packedBuffer.AddToBack(pvData,dwDataSize)) != DPN_OK) { DPFERR("Could not add Data to back of buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dwDataOffset = packedBuffer.GetTailOffset(); pMsg->dwDataSize = dwDataSize; } else { pMsg->dwDataOffset = 0; pMsg->dwDataSize = 0; } pMsg->dpnid = dpnid; pMsg->dwInfoFlags = dwInfoFlags; pMsg->dwVersion = dwVersion; pMsg->dwVersionNotUsed = 0; pMsg->dpnidRequesting = dpnidRequesting; pMsg->hCompletionOp = hCompletionOp;
//
// SEND UpdateInfo messages via WorkerThread
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create new WorkerJob"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
#ifndef DPNBUILD_NOSERVER
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) #endif // DPNBUILD_NOSERVER
{ pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); } #ifndef DPNBUILD_NOSERVER
else if ((pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) && fHostRequested) { // Send to everyone except the server
pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( dpnidRequesting ); } else { DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER);
// This will be responding to a client that requested its
// info updated via SetClientInfo
// Use the Exclude DPNID as the address to send to
pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION_CLIENT ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( dpnidRequesting ); } #endif // DPNBUILD_NOSERVER
pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_UPDATE_INFO ); pWorkerJob->SetSendNameTableOperationVersion( dwVersion ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL; } } pNTEntry->Release(); pNTEntry = NULL;
//
// If this was called by the local (Host) player,
// Check to see if this was an original operation or a re-try from HostMigration
//
// If this was an original operation,
// See if we need an Async HANDLE for the user
// Otherwise
// Clean up the outstanding operation
//
if (fHostRequested) { if (hCompletionOp == 0) // Original
{ DBG_CASSERT( DPNSETGROUPINFO_SYNC == DPNSETCLIENTINFO_SYNC ); DBG_CASSERT( DPNSETCLIENTINFO_SYNC == DPNSETSERVERINFO_SYNC ); DBG_CASSERT( DPNSETSERVERINFO_SYNC == DPNSETPEERINFO_SYNC ); //
// If this fails, or is synchronous, return the operation result immediately
//
if (!(dwFlags & (DPNSETGROUPINFO_SYNC | DPNSETCLIENTINFO_SYNC | DPNSETSERVERINFO_SYNC | DPNSETPEERINFO_SYNC)) && (hrOperation == DPN_OK)) { if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK) { DPFERR("Could not create Async HANDLE"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pHandleParent->SetCompletion( DNCompleteAsyncHandle ); pHandleParent->SetContext( pvUserContext ); pHandleParent->SetResult( hrOperation ); pHandleParent->SetCannotCancel(); *phAsyncOp = pHandleParent->GetHandle(); pHandleParent->Release(); pHandleParent = NULL;
hResultCode = DPNERR_PENDING; } else { hResultCode = hrOperation; } } else // Host Migration re-try
{ CAsyncOp *pRequest;
pRequest = NULL;
if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pRequest ))) { pRequest->SetResult( hrOperation );
// Release the HandleTable reference
pRequest->Release(); } pRequest = NULL;
hResultCode = DPN_OK; } } else { hResultCode = DPN_OK; }
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (!fHostRequested) { DNHostFailRequest(pdnObject,dpnidRequesting,hCompletionOp,hrOperation); } else { //
// If a completion op was specified and this was requested by the Host, this is a
// retry of an operation during Host migration. In this case, we want to set the
// result (failure code) of the completion op, and remove it from the HandleTable.
//
if (hCompletionOp) { CAsyncOp *pHostCompletionOp;
pHostCompletionOp = NULL; if (SUCCEEDED(pdnObject->HandleTable.Destroy( hCompletionOp, (PVOID*)&pHostCompletionOp ))) { pHostCompletionOp->SetResult( hResultCode );
// Release the HandleTable reference
pHostCompletionOp->Release(); } pHostCompletionOp = NULL;
DNASSERT(pHostCompletionOp == NULL); } } if (pHandleParent) { pHandleParent->Release(); pHandleParent = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
// DNHostCheckIntegrity
//
// The host has been asked to perform an integrity check. We will send a message to the
// target player with the DPNID of the requesting player. If this is returned to us, we
// will destroy the requesting player.
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostCheckIntegrity"
HRESULT DNHostCheckIntegrity(DIRECTNETOBJECT *const pdnObject, const DPNID dpnidTarget, const DPNID dpnidRequesting) { HRESULT hResultCode; CNameTableEntry *pNTEntry; CConnection *pConnection; CRefCountBuffer *pRefCountBuffer; DN_INTERNAL_MESSAGE_INTEGRITY_CHECK *pMsg;
DPFX(DPFPREP, 6,"Parameters: dpnidTarget [0x%lx], dpnidRequesting [0x%lx]",dpnidTarget,dpnidRequesting);
pNTEntry = NULL; pConnection = NULL; pRefCountBuffer = NULL;
//
// Ensure that the target player is still in the NameTable, as we might have deleted him already
//
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnidTarget,&pNTEntry)) != DPN_OK) { DPFERR("Could not find integrity check target in NameTable - probably deleted already"); DisplayDNError(0,hResultCode); hResultCode = DPN_OK; goto Failure; } if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get target player connection reference - probably deleted already"); DisplayDNError(0,hResultCode); hResultCode = DPN_OK; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Create the message
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_INTEGRITY_CHECK), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_INTEGRITY_CHECK*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnidRequesting = dpnidRequesting;
//
// Send message
//
if ((hResultCode = DNSendMessage( pdnObject, pConnection, DN_MSG_INTERNAL_INTEGRITY_CHECK, dpnidTarget, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL )) != DPNERR_PENDING) { DPFERR("Could not send message - probably deleted already"); DisplayDNError(0,hResultCode); DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
hResultCode = DPN_OK; goto Failure; }
pConnection->Release(); pConnection = NULL; pRefCountBuffer->Release(); pRefCountBuffer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
// DNHostFixIntegrity
//
// The host has received a response from a player whose session integrity was being checked.
// The player who requested this check will be dropped.
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostFixIntegrity"
HRESULT DNHostFixIntegrity(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; CNameTableEntry *pNTEntry; CConnection *pConnection; CRefCountBuffer *pRefCountBuffer; UNALIGNED DN_INTERNAL_MESSAGE_INTEGRITY_CHECK_RESPONSE *pResponse; DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
DPFX(DPFPREP, 6,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pNTEntry = NULL; pConnection = NULL; pRefCountBuffer = NULL;
pResponse = static_cast<DN_INTERNAL_MESSAGE_INTEGRITY_CHECK_RESPONSE*>(pvBuffer);
//
// Get requesting player's connection - they may have already dropped
//
if ((hResultCode = pdnObject->NameTable.FindEntry(pResponse->dpnidRequesting,&pNTEntry)) != DPN_OK) { DPFERR("Could not find player in NameTable - may have dropped"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get player connection reference"); DisplayDNError(0,hResultCode); goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Build terminate message
//
if ((hResultCode = RefCountBufferNew(pdnObject,sizeof(DN_INTERNAL_MESSAGE_TERMINATE_SESSION),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not allocate RefCountBuffer"); DisplayDNError(0,hResultCode); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pRefCountBuffer->GetBufferAddress()); pMsg->dwTerminateDataOffset = 0; pMsg->dwTerminateDataSize = 0;
//
// Send message to player to exit
//
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_TERMINATE_SESSION, pResponse->dpnidRequesting, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL);
pConnection->Release(); pConnection = NULL; pRefCountBuffer->Release(); pRefCountBuffer = NULL;
//
// Disconnect player
//
hResultCode = DNHostDisconnect(pdnObject,pResponse->dpnidRequesting,DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessCreateGroup"
HRESULT DNProcessCreateGroup(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry; CAsyncOp *pRequest; UNALIGNED DN_NAMETABLE_ENTRY_INFO *pInfo; UNALIGNED DN_INTERNAL_MESSAGE_CREATE_GROUP *pMsg; BOOL fNotify;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pRequest = NULL; pLocalPlayer = NULL; pNTEntry = NULL;
pMsg = static_cast<DN_INTERNAL_MESSAGE_CREATE_GROUP*>(pvBuffer); pInfo = reinterpret_cast<DN_NAMETABLE_ENTRY_INFO*>(pMsg + 1);
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Create Group
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pNTEntry)) != DPN_OK) { DPFERR("Could not create new NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((hResultCode = pNTEntry->UnpackEntryInfo(pInfo,static_cast<BYTE*>(pvBuffer))) != DPN_OK) { DPFERR("Could not unpack NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
//
// Get async op if we requested this operation - it has the group context on it
//
if (pMsg->dpnidRequesting == pLocalPlayer->GetDPNID()) { pdnObject->HandleTable.Lock(); if ((hResultCode = pdnObject->HandleTable.Find( pMsg->hCompletionOp,(PVOID*)&pRequest )) != DPN_OK) { pdnObject->HandleTable.Unlock(); DPFERR("Could not find REQUEST AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } else { pRequest->AddRef(); pdnObject->HandleTable.Unlock(); } pNTEntry->SetContext( pRequest->GetContext() ); } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Add Group to NameTable
//
if ((hResultCode = pdnObject->NameTable.InsertEntry(pNTEntry)) != DPN_OK) { DPFERR("Could not update NameTable"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion(pNTEntry->GetVersion()); pdnObject->NameTable.Unlock();
fNotify = FALSE; pNTEntry->Lock(); if (!pNTEntry->IsAvailable() && !pNTEntry->IsDisconnecting()) { pNTEntry->MakeAvailable(); pNTEntry->NotifyAddRef(); pNTEntry->NotifyAddRef(); pNTEntry->SetInUse(); fNotify = TRUE; } pNTEntry->Unlock();
if (fNotify) { DNUserCreateGroup(pdnObject,pNTEntry);
pNTEntry->PerformQueuedOperations(); }
pNTEntry->Release(); pNTEntry = NULL;
//
// If this is a completion, set result and remove it from the request list and handle table
//
if (pRequest) { DNEnterCriticalSection(&pdnObject->csActiveList); pRequest->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList);
pRequest->SetResult( DPN_OK ); if (SUCCEEDED(pdnObject->HandleTable.Destroy( pMsg->hCompletionOp, NULL ))) { // Release the HandleTable reference
pRequest->Release(); } pRequest->Release(); pRequest = NULL; }
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRequest) { pRequest->Release(); pRequest = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessDestroyGroup"
HRESULT DNProcessDestroyGroup(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; DWORD dwVersion; CNameTableEntry *pLocalPlayer; CAsyncOp *pRequest; UNALIGNED DN_INTERNAL_MESSAGE_DESTROY_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pLocalPlayer = NULL; pRequest = NULL;
pMsg = static_cast<DN_INTERNAL_MESSAGE_DESTROY_GROUP*>(pvBuffer);
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Destroy Group
//
dwVersion = pMsg->dwVersion; if ((hResultCode = pdnObject->NameTable.DeleteGroup(pMsg->dpnidGroup,&dwVersion)) != DPN_OK) { DPFERR("Could not delete group from NameTable"); DisplayDNError(0,hResultCode);
//
// Update version in any event (to prevent NameTable hangs)
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pMsg->dwVersion ); pdnObject->NameTable.Unlock();
goto Failure; }
//
// If this is a completion, set the result and remove it from the request list and handle table
//
if (pMsg->dpnidRequesting == pLocalPlayer->GetDPNID()) { if ((hResultCode = pdnObject->HandleTable.Destroy( pMsg->hCompletionOp,(PVOID*)&pRequest )) != DPN_OK) { DPFERR("Could not find REQUEST AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } DNEnterCriticalSection(&pdnObject->csActiveList); pRequest->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList);
pRequest->SetResult( DPN_OK ); pRequest->Release(); pRequest = NULL; } pLocalPlayer->Release(); pLocalPlayer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRequest) { pRequest->Release(); pRequest = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessAddPlayerToGroup"
HRESULT DNProcessAddPlayerToGroup(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; DWORD dwVersion; CNameTableEntry *pLocalPlayer; CNameTableEntry *pGroup; CNameTableEntry *pPlayer; CAsyncOp *pRequest; UNALIGNED DN_INTERNAL_MESSAGE_ADD_PLAYER_TO_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pLocalPlayer = NULL; pGroup = NULL; pPlayer = NULL; pRequest = NULL;
pMsg = static_cast<DN_INTERNAL_MESSAGE_ADD_PLAYER_TO_GROUP*>(pvBuffer);
//
// Get NameTable entries
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = pdnObject->NameTable.FindEntry(pMsg->dpnidGroup,&pGroup)) != DPN_OK) { DPFERR("Could not find group"); DisplayDNError(0,hResultCode);
//
// Update version in any event (to prevent NameTable hangs)
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pMsg->dwVersion ); pdnObject->NameTable.Unlock();
goto Failure; } if ((hResultCode = pdnObject->NameTable.FindEntry(pMsg->dpnidPlayer,&pPlayer)) != DPN_OK) { DPFERR("Could not find player"); DisplayDNError(0,hResultCode);
//
// Update version in any event (to prevent NameTable hangs)
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pMsg->dwVersion ); pdnObject->NameTable.Unlock();
goto Failure; }
//
// Add Player To Group
//
dwVersion = pMsg->dwVersion; if ((hResultCode = pdnObject->NameTable.AddPlayerToGroup(pGroup,pPlayer,&dwVersion)) != DPN_OK) { DPFERR("Could not add player to group"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pGroup->Release(); pGroup = NULL; pPlayer->Release(); pPlayer = NULL;
//
// If this is a completion, set result and remove it from the request list and handle table
//
if (pMsg->dpnidRequesting == pLocalPlayer->GetDPNID()) { if ((hResultCode = pdnObject->HandleTable.Destroy( pMsg->hCompletionOp,(PVOID*)&pRequest )) != DPN_OK) { DPFERR("Could not find REQUEST AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } DNEnterCriticalSection(&pdnObject->csActiveList); pRequest->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList);
pRequest->SetResult( DPN_OK ); pRequest->Release(); pRequest = NULL; } pLocalPlayer->Release(); pLocalPlayer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRequest) { pRequest->Release(); pRequest = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pGroup) { pGroup->Release(); pGroup = NULL; } if (pPlayer) { pPlayer->Release(); pPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessDeletePlayerFromGroup"
HRESULT DNProcessDeletePlayerFromGroup(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; DWORD dwVersion; CNameTableEntry *pLocalPlayer; CNameTableEntry *pGroup; CNameTableEntry *pPlayer; CAsyncOp *pRequest; UNALIGNED DN_INTERNAL_MESSAGE_DELETE_PLAYER_FROM_GROUP *pMsg;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pLocalPlayer = NULL; pGroup = NULL; pPlayer = NULL; pRequest = NULL;
pMsg = static_cast<DN_INTERNAL_MESSAGE_DELETE_PLAYER_FROM_GROUP*>(pvBuffer);
//
// Get NameTable entries
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = pdnObject->NameTable.FindEntry(pMsg->dpnidGroup,&pGroup)) != DPN_OK) { DPFERR("Could not find group"); DisplayDNError(0,hResultCode);
//
// Update version in any event (to prevent NameTable hangs)
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pMsg->dwVersion ); pdnObject->NameTable.Unlock();
goto Failure; } if ((hResultCode = pdnObject->NameTable.FindEntry(pMsg->dpnidPlayer,&pPlayer)) != DPN_OK) { DPFERR("Could not find player"); DisplayDNError(0,hResultCode);
//
// Update version in any event (to prevent NameTable hangs)
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pMsg->dwVersion ); pdnObject->NameTable.Unlock();
goto Failure; }
//
// Delete Player From Group
//
dwVersion = pMsg->dwVersion; if ((hResultCode = pdnObject->NameTable.RemovePlayerFromGroup(pGroup,pPlayer,&dwVersion)) != DPN_OK) { DPFERR("Could not delete player from group"); DisplayDNError(0,hResultCode); goto Failure; } pGroup->Release(); pGroup = NULL; pPlayer->Release(); pPlayer = NULL;
//
// If this is a completion, set the result and remove it from the request list and handle table
//
if (pMsg->dpnidRequesting == pLocalPlayer->GetDPNID()) { if ((hResultCode = pdnObject->HandleTable.Destroy( pMsg->hCompletionOp,(PVOID*)&pRequest )) != DPN_OK) { DPFERR("Could not find REQUEST AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } DNEnterCriticalSection(&pdnObject->csActiveList); pRequest->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList);
pRequest->SetResult( DPN_OK ); pRequest->Release(); pRequest = NULL; } pLocalPlayer->Release(); pLocalPlayer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRequest) { pRequest->Release(); pRequest = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pGroup) { pGroup->Release(); pGroup = NULL; } if (pPlayer) { pPlayer->Release(); pPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessUpdateInfo"
HRESULT DNProcessUpdateInfo(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; PWSTR pwszName; PVOID pvData; CNameTableEntry *pLocalPlayer; CNameTableEntry *pNTEntry; CAsyncOp *pRequest; UNALIGNED DN_INTERNAL_MESSAGE_UPDATE_INFO *pMsg; BOOL fDoUpdate = TRUE;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pLocalPlayer = NULL; pNTEntry = NULL; pRequest = NULL;
pMsg = static_cast<DN_INTERNAL_MESSAGE_UPDATE_INFO*>(pvBuffer);
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; }
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { //
// Update Info
//
if ((hResultCode = pdnObject->NameTable.FindEntry(pMsg->dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find NameTableEntry"); DisplayDNError(0,hResultCode);
//
// Update version in any event (to prevent NameTable hangs)
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pMsg->dwVersion ); pdnObject->NameTable.Unlock();
goto Failure; } } else { DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT);
// We are either being told that the host info has changed by a call
// on the Host to SetServerInfo, or we are being told that our own
// request to the server to change this Client's info has completed.
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef(&pNTEntry)) != DPN_OK) { DPFERR("Could not find Host NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if (pNTEntry->GetDPNID() == pMsg->dpnid) { DPFX(DPFPREP, 5,"Updating server info"); } else if (pLocalPlayer->GetDPNID() == pMsg->dpnid) { fDoUpdate = FALSE; DPFX(DPFPREP, 5,"Completing updating client info"); } else { DPFERR("Received UpdateInfo for bad DPNID"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } }
if (fDoUpdate) { if ((pMsg->dwInfoFlags & DPNINFO_NAME) && (pMsg->dwNameOffset)) { pwszName = reinterpret_cast<WCHAR*>(static_cast<BYTE*>(pvBuffer) + pMsg->dwNameOffset); } else { pwszName = NULL; } if ((pMsg->dwInfoFlags & DPNINFO_DATA) && (pMsg->dwDataOffset)) { pvData = static_cast<void*>(static_cast<BYTE*>(pvBuffer) + pMsg->dwDataOffset); } else { pvData = NULL; }
// This function takes the lock internally
pNTEntry->UpdateEntryInfo(pwszName,pMsg->dwNameSize,pvData,pMsg->dwDataSize,pMsg->dwInfoFlags, TRUE); }
pNTEntry->Release(); pNTEntry = NULL;
//
// Set NameTable version
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion(pMsg->dwVersion); pdnObject->NameTable.Unlock();
//
// If this is a completion, set the result and remove it from the request list and handle table
//
if (pMsg->dpnidRequesting == pLocalPlayer->GetDPNID()) { if ((hResultCode = pdnObject->HandleTable.Destroy( pMsg->hCompletionOp,(PVOID*)&pRequest )) != DPN_OK) { DPFERR("Could not find REQUEST AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } DNEnterCriticalSection(&pdnObject->csActiveList); pRequest->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList);
pRequest->SetResult( DPN_OK ); pRequest->Release(); pRequest = NULL; } pLocalPlayer->Release(); pLocalPlayer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRequest) { pRequest->Release(); pRequest = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessFailedRequest"
HRESULT DNProcessFailedRequest(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; CAsyncOp *pRequest; UNALIGNED DN_INTERNAL_MESSAGE_REQUEST_FAILED *pMsg;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pRequest = NULL;
pMsg = static_cast<DN_INTERNAL_MESSAGE_REQUEST_FAILED*>(pvBuffer);
//
// Update request using handle to HRESULT passed back by Host, and remove request from request list and handle table
//
if ((hResultCode = pdnObject->HandleTable.Destroy( pMsg->hCompletionOp, (PVOID*)&pRequest )) == DPN_OK) { DNASSERT( pMsg->hCompletionOp != 0 );
DNEnterCriticalSection(&pdnObject->csActiveList); pRequest->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList);
pRequest->SetResult( pMsg->hResultCode );
pRequest->Release(); pRequest = NULL; } hResultCode = DPN_OK;
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
// DNProcessCheckIntegrity
//
// The host is performing an integrity check and is asking the local player (us) if we are still
// in the session. We will respond that we are, and the host will drop the requesting player.
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessCheckIntegrity"
HRESULT DNProcessCheckIntegrity(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer) { HRESULT hResultCode; CNameTableEntry *pHostPlayer; CConnection *pConnection; CRefCountBuffer *pRefCountBuffer; UNALIGNED DN_INTERNAL_MESSAGE_INTEGRITY_CHECK *pMsg; DN_INTERNAL_MESSAGE_INTEGRITY_CHECK_RESPONSE *pResponse;
DPFX(DPFPREP, 6,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pHostPlayer = NULL; pConnection = NULL; pRefCountBuffer = NULL;
//
// Get host player connection to respond to
//
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) != DPN_OK) { DPFERR("Could not get host player reference"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = pHostPlayer->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get host player connection reference"); DisplayDNError(0,hResultCode); goto Failure; } pHostPlayer->Release(); pHostPlayer = NULL;
//
// Create response
//
if ((hResultCode = RefCountBufferNew(pdnObject,sizeof(DN_INTERNAL_MESSAGE_INTEGRITY_CHECK_RESPONSE),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pResponse = reinterpret_cast<DN_INTERNAL_MESSAGE_INTEGRITY_CHECK_RESPONSE*>(pRefCountBuffer->GetBufferAddress()); pMsg = static_cast<DN_INTERNAL_MESSAGE_INTEGRITY_CHECK*>(pvBuffer); pResponse->dpnidRequesting = pMsg->dpnidRequesting;
//
// Send response
//
if ((hResultCode = DNSendMessage( pdnObject, pConnection, DN_MSG_INTERNAL_INTEGRITY_CHECK_RESPONSE, pConnection->GetDPNID(), pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL )) != DPNERR_PENDING) { DPFERR("Could not send integrity check response"); DisplayDNError(0,hResultCode); DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
goto Failure; }
pConnection->Release(); pConnection = NULL; pRefCountBuffer->Release(); pRefCountBuffer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pHostPlayer) { pHostPlayer->Release(); pHostPlayer = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
|