You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3687 lines
96 KiB
3687 lines
96 KiB
/*==========================================================================
|
|
*
|
|
* 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;
|
|
}
|
|
|