Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1166 lines
31 KiB

/*==========================================================================
*
* Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
*
* File: NTOpList.cpp
* Content: DirectNet NameTable Operation List
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 01/19/00 mjn Created
* 01/20/00 mjn Added DNNTOLGetVersion,DNNTOLDestroyEntry,
* DNNTOLCleanUp,DNNTOLProcessOperation
* 01/21/00 mjn Host ACKnowledgements contain the actual op and not the REQuest
* 01/24/00 mjn Implemented NameTable operation list version cleanup
* 01/25/00 mjn Send dwLatestVersion to Host at migration
* 01/25/00 mjn Added pending operation list routines DNPOAdd and DNPORun
* 01/26/00 mjn Added DNNTOLFindEntry
* 04/19/00 mjn Update NameTable operations to use DN_WORKER_JOB_SEND_NAMETABLE_OPERATION
* 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer()
* 07/19/00 mjn Added DNPOCleanUp()
* 07/31/00 mjn Change DN_MSG_INTERNAL_DELETE_PLAYER to DN_MSG_INTERNAL_DESTROY_PLAYER
* 08/08/00 mjn Ensure DNOLPlayerSendVersion() takes player reference correctly
* 08/24/00 mjn Added CNameTableOp (to replace DN_NAMETABLE_OP)
* 09/17/00 mjn Split CNameTable.m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups
* 09/28/00 mjn Fixed logic error in DNNTAddOperation()
* 01/25/01 mjn Fixed 64-bit alignment problem in DNNTGetOperationVersion()
* 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's
* mjn Added service provider to DNNTAddOperation()
* 04/05/01 mjn Overwrite old NameTable operations with newer ones in DNNTAddOperation()
* 04/11/01 mjn Cleanup and return CNameTableOp if replaced in DNNTAddOperation()
* 07/22/01 mjn Added DPNBUILD_NOHOSTMIGRATE compile flag
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dncorei.h"
#ifndef DPNBUILD_NOHOSTMIGRATE
// DNNTHostReceiveVersion
//
// Update the NameTable version of a player's entry in the Host player's NameTable
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTHostReceiveVersion"
HRESULT DNNTHostReceiveVersion(DIRECTNETOBJECT *const pdnObject,
const DPNID dpnid,
void *const pMsg)
{
HRESULT hResultCode;
CNameTableEntry *pNTEntry;
UNALIGNED DN_INTERNAL_MESSAGE_NAMETABLE_VERSION *pInfo;
DPFX(DPFPREP, 6,"Parameters: dpnid [0x%lx], pMsg [0x%p]",dpnid,pMsg);
DNASSERT(pdnObject != NULL);
DNASSERT(pMsg != NULL);
pNTEntry = NULL;
pInfo = static_cast<DN_INTERNAL_MESSAGE_NAMETABLE_VERSION*>(pMsg);
//
// Find player's entry in NameTable
//
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK)
{
DPFERR("Player no longer in NameTable");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDPLAYER;
goto Failure;
}
//
// Update version number of entry
//
DPFX(DPFPREP, 7,"Set player [0x%lx] dwLatestVersion [%ld]", dpnid,pInfo->dwVersion);
pNTEntry->Lock();
pNTEntry->SetLatestVersion(pInfo->dwVersion);
pNTEntry->Unlock();
pNTEntry->Release();
pNTEntry = NULL;
//
// If the host is migrating, see if we can continue
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING)
{
DNCheckReceivedAllVersions(pdnObject);
}
else
{
DWORD dwOldestVersion;
BOOL fReSync;
CBilink *pBilink;
//
// Determine the oldest version EVERYONE has updated to
//
fReSync = FALSE;
dwOldestVersion = pInfo->dwVersion;
pdnObject->NameTable.ReadLock();
pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
{
pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
pNTEntry->Lock();
if (pNTEntry->IsAvailable() && !pNTEntry->IsHost())
{
if (pNTEntry->GetLatestVersion() < dwOldestVersion)
{
dwOldestVersion = pNTEntry->GetLatestVersion();
}
}
pNTEntry->Unlock();
pNTEntry = NULL;
pBilink = pBilink->GetNext();
}
if (dwOldestVersion > pdnObject->NameTable.GetLatestVersion())
{
fReSync = TRUE;
}
pdnObject->NameTable.Unlock();
//
// Resync NameTable versions of other players if required
//
if (fReSync)
{
DNNTHostResyncVersion(pdnObject,dwOldestVersion);
}
}
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pNTEntry)
{
pNTEntry->Release();
pNTEntry = NULL;
}
goto Exit;
}
#endif // DPNBUILD_NOHOSTMIGRATE
#ifndef DPNBUILD_NOHOSTMIGRATE
// DNNTPlayerSendVersion
//
// Send the Local player's NameTable version to the Host
// This should only be called in Peer-to-Peer mode
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTPlayerSendVersion"
HRESULT DNNTPlayerSendVersion(DIRECTNETOBJECT *const pdnObject)
{
HRESULT hResultCode;
CNameTableEntry *pHostPlayer;
CRefCountBuffer *pRefCountBuffer;
CWorkerJob *pWorkerJob;
DN_INTERNAL_MESSAGE_NAMETABLE_VERSION *pInfo;
DPFX(DPFPREP, 6,"Parameters: (none)");
DNASSERT(pdnObject != NULL);
DNASSERT(pdnObject->dwFlags & DN_OBJECT_FLAG_PEER);
pHostPlayer = NULL;
pRefCountBuffer = NULL;
pWorkerJob = NULL;
//
// Get Host player reference
//
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) != DPN_OK)
{
DPFERR("Could not find Host player");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_NOHOSTPLAYER;
goto Failure;
}
//
// Host player updates entry directly
//
if (pHostPlayer->IsLocal())
{
DWORD dwVersion;
pdnObject->NameTable.ReadLock();
dwVersion = pdnObject->NameTable.GetVersion();
pdnObject->NameTable.Unlock();
DPFX(DPFPREP, 7,"Set Host player dwLatestVersion [%ld]",dwVersion);
pHostPlayer->Lock();
pHostPlayer->SetLatestVersion(dwVersion);
pHostPlayer->Unlock();
}
else
{
//
// Create message and send to Host player
//
hResultCode = RefCountBufferNew(pdnObject,
sizeof(DN_INTERNAL_MESSAGE_NAMETABLE_VERSION),
MemoryBlockAlloc,
MemoryBlockFree,
&pRefCountBuffer);
if (hResultCode != DPN_OK)
{
DPFERR("Could not allocate space for RefCount buffer");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_NAMETABLE_VERSION*>(pRefCountBuffer->GetBufferAddress());
pdnObject->NameTable.ReadLock();
pInfo->dwVersion = pdnObject->NameTable.GetVersion();
pInfo->dwVersionNotUsed = 0;
pdnObject->NameTable.Unlock();
DPFX(DPFPREP, 7,"Send Local player dwLatestVersion [%ld]",pInfo->dwVersion);
//
// Send message to host player
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
{
DPFERR("Could not create worker job");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_VERSION );
pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob);
pWorkerJob = NULL;
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
pHostPlayer->Release();
pHostPlayer = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pHostPlayer)
{
pHostPlayer->Release();
pHostPlayer = NULL;
}
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
goto Exit;
}
#endif // DPNBUILD_NOHOSTMIGRATE
#ifndef DPNBUILD_NOHOSTMIGRATE
// DNNTHostResyncVersion
//
// Re-sync of the NameTable operation lists based on lowest common version number
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTHostResyncVersion"
HRESULT DNNTHostResyncVersion(DIRECTNETOBJECT *const pdnObject,
const DWORD dwVersion)
{
HRESULT hResultCode;
CRefCountBuffer *pRefCountBuffer;
CWorkerJob *pWorkerJob;
DN_INTERNAL_MESSAGE_RESYNC_VERSION *pInfo;
DPFX(DPFPREP, 6,"Parameters: dwVersion [%ld]",dwVersion);
DNASSERT(pdnObject != NULL);
pWorkerJob = NULL;
pRefCountBuffer = NULL;
//
// Create re-sync message
//
if ((hResultCode = RefCountBufferNew(pdnObject,sizeof(DN_INTERNAL_MESSAGE_RESYNC_VERSION),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
{
DPFERR("Could not allocate RefCount buffer");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pInfo = (DN_INTERNAL_MESSAGE_RESYNC_VERSION *)(pRefCountBuffer->GetBufferAddress());
pInfo->dwVersion = dwVersion;
pInfo->dwVersionNotUsed = 0;
//
// Hand this to worker thread
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
{
DPFERR("Could not allocate new worker thread job");
DisplayDNError(0,hResultCode);
goto Failure;
}
pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_RESYNC_VERSION );
pWorkerJob->SetSendNameTableOperationVersion( 0 );
pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob);
pWorkerJob = NULL;
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
if (pWorkerJob)
{
pWorkerJob->ReturnSelfToPool();
pWorkerJob = NULL;
}
goto Exit;
}
#endif // DPNBUILD_NOHOSTMIGRATE
#ifndef DPNBUILD_NOHOSTMIGRATE
// DNNTPlayerResyncVersion
//
// Re-sync of the NameTable operation list from Host player
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTPlayerResyncVersion"
HRESULT DNNTPlayerResyncVersion(DIRECTNETOBJECT *const pdnObject,
void *const pMsg)
{
HRESULT hResultCode;
UNALIGNED DN_INTERNAL_MESSAGE_RESYNC_VERSION *pInfo;
DPFX(DPFPREP, 6,"Parameters: pMsg [0x%p]",pMsg);
DNASSERT(pdnObject != NULL);
DNASSERT(pMsg != NULL);
pInfo = static_cast<DN_INTERNAL_MESSAGE_RESYNC_VERSION*>(pMsg);
DPFX(DPFPREP, 5,"Instructed to clean up NameTable operation list dwVersion < [%ld]",
pInfo->dwVersion);
DNNTRemoveOperations(pdnObject,pInfo->dwVersion,FALSE);
hResultCode = DPN_OK;
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#endif // DPNBUILD_NOHOSTMIGRATE
// DNNTGetOperationVersion
//
// Find the version number of a NameTable Operation
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTGetOperationVersion"
HRESULT DNNTGetOperationVersion(DIRECTNETOBJECT *const pdnObject,
const DWORD dwMsgId,
void *const pOpBuffer,
const DWORD dwOpBufferSize,
DWORD *const pdwVersion,
DWORD *const pdwVersionNotUsed)
{
HRESULT hResultCode;
DPFX(DPFPREP, 6,"Parameters: dwMsgId [0x%lx], pOpBuffer [0x%p], dwOpBufferSize [%ld], pdwVersion [0x%p]",
dwMsgId,pOpBuffer,dwOpBufferSize,pdwVersion);
DNASSERT(pdwVersion != NULL);
DNASSERT(pdwVersionNotUsed != NULL);
hResultCode = DPN_OK;
switch (dwMsgId)
{
case DN_MSG_INTERNAL_INSTRUCT_CONNECT:
{
*pdwVersion = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT*>(pOpBuffer)->dwVersion;
*pdwVersionNotUsed = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT *>(pOpBuffer)->dwVersionNotUsed;
break;
}
case DN_MSG_INTERNAL_ADD_PLAYER:
{
*pdwVersion = static_cast<UNALIGNED DN_NAMETABLE_ENTRY_INFO *>(pOpBuffer)->dwVersion;
*pdwVersionNotUsed = static_cast<UNALIGNED DN_NAMETABLE_ENTRY_INFO *>(pOpBuffer)->dwVersionNotUsed;
break;
}
case DN_MSG_INTERNAL_DESTROY_PLAYER:
{
*pdwVersion = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_DESTROY_PLAYER *>(pOpBuffer)->dwVersion;
*pdwVersionNotUsed = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_DESTROY_PLAYER *>(pOpBuffer)->dwVersionNotUsed;
break;
}
case DN_MSG_INTERNAL_CREATE_GROUP:
{
*pdwVersion = (reinterpret_cast<UNALIGNED DN_NAMETABLE_ENTRY_INFO*>((static_cast<DN_INTERNAL_MESSAGE_CREATE_GROUP*>(pOpBuffer)) + 1))->dwVersion;
*pdwVersionNotUsed = (reinterpret_cast<UNALIGNED DN_NAMETABLE_ENTRY_INFO*>((static_cast<DN_INTERNAL_MESSAGE_CREATE_GROUP*>(pOpBuffer)) + 1))->dwVersionNotUsed;
break;
}
case DN_MSG_INTERNAL_DESTROY_GROUP:
{
*pdwVersion = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_DESTROY_GROUP*>(pOpBuffer)->dwVersion;
*pdwVersionNotUsed = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_DESTROY_GROUP*>(pOpBuffer)->dwVersionNotUsed;
break;
}
case DN_MSG_INTERNAL_ADD_PLAYER_TO_GROUP:
{
*pdwVersion = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_ADD_PLAYER_TO_GROUP*>(pOpBuffer)->dwVersion;
*pdwVersionNotUsed = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_ADD_PLAYER_TO_GROUP*>(pOpBuffer)->dwVersionNotUsed;
break;
}
case DN_MSG_INTERNAL_DELETE_PLAYER_FROM_GROUP:
{
*pdwVersion = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_DELETE_PLAYER_FROM_GROUP*>(pOpBuffer)->dwVersion;
*pdwVersionNotUsed = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_DELETE_PLAYER_FROM_GROUP*>(pOpBuffer)->dwVersionNotUsed;
break;
}
case DN_MSG_INTERNAL_UPDATE_INFO:
{
*pdwVersion = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_UPDATE_INFO*>(pOpBuffer)->dwVersion;
*pdwVersionNotUsed = static_cast<UNALIGNED DN_INTERNAL_MESSAGE_UPDATE_INFO*>(pOpBuffer)->dwVersionNotUsed;
break;
}
default:
{
DPFERR("Invalid MessageID");
DNASSERT(FALSE);
hResultCode = DPNERR_UNSUPPORTED;
}
}
if (hResultCode == DPN_OK)
{
DPFX(DPFPREP, 7,"*pdwVersion = [%ld]",*pdwVersion);
}
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTPerformOperation"
HRESULT DNNTPerformOperation(DIRECTNETOBJECT *const pdnObject,
const DWORD dwMsgId,
void *const pvBuffer)
{
HRESULT hResultCode;
DPFX(DPFPREP, 6,"Parameters: dwMsgId [0x%lx], pvBuffer [0x%p]",dwMsgId,pvBuffer);
switch (dwMsgId)
{
case DN_MSG_INTERNAL_INSTRUCT_CONNECT:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_INSTRUCT_CONNECT");
if ((hResultCode = DNConnectToPeer2(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Instructed connect failed");
DisplayDNError(0,hResultCode);
}
break;
}
case DN_MSG_INTERNAL_ADD_PLAYER:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_ADD_PLAYER");
if ((hResultCode = DNConnectToPeer1(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Add player failed");
DisplayDNError(0,hResultCode);
}
break;
}
case DN_MSG_INTERNAL_DESTROY_PLAYER:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_DESTROY_PLAYER");
if ((hResultCode = DNInstructedDisconnect(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Destroy player failed");
DisplayDNError(0,hResultCode);
}
break;
}
case DN_MSG_INTERNAL_CREATE_GROUP:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_CREATE_GROUP");
if ((hResultCode = DNProcessCreateGroup(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Create group failed");
DisplayDNError(0,hResultCode);
}
break;
}
case DN_MSG_INTERNAL_DESTROY_GROUP:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_DESTROY_GROUP");
if ((hResultCode = DNProcessDestroyGroup(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Destroy group failed");
DisplayDNError(0,hResultCode);
}
break;
}
case DN_MSG_INTERNAL_ADD_PLAYER_TO_GROUP:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_ADD_PLAYER_TO_GROUP");
if ((hResultCode = DNProcessAddPlayerToGroup(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Add player to group failed");
DisplayDNError(0,hResultCode);
}
break;
}
case DN_MSG_INTERNAL_DELETE_PLAYER_FROM_GROUP:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_DELETE_PLAYER_FROM_GROUP");
if ((hResultCode = DNProcessDeletePlayerFromGroup(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Remove player from group failed");
DisplayDNError(0,hResultCode);
}
break;
}
case DN_MSG_INTERNAL_UPDATE_INFO:
{
DPFX(DPFPREP, 7,"Perform DN_MSG_INTERNAL_UPDATE_INFO");
if ((hResultCode = DNProcessUpdateInfo(pdnObject,pvBuffer)) != DPN_OK)
{
DPFERR("Update info failed");
DisplayDNError(0,hResultCode);
}
break;
}
default:
{
DPFERR("Invalid MessageID");
DNASSERT(FALSE);
return(DPNERR_UNSUPPORTED);
}
}
hResultCode = DPN_OK;
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DNNTAddOperation
//
// Add an operation to the NameTable operation list
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTAddOperation"
HRESULT DNNTAddOperation(DIRECTNETOBJECT *const pdnObject,
const DWORD dwMsgId,
void *const pOpBuffer,
const DWORD dwOpBufferSize,
const HANDLE hProtocol,
CServiceProvider *const pSP)
#ifndef DPNBUILD_NOHOSTMIGRATE
{
HRESULT hResultCode;
CRefCountBuffer *pRefCountBuffer;
CNameTableOp *pNTOp;
BOOL fReSync;
DPFX(DPFPREP, 4,"Parameters: dwMsgId [0x%lx], pOpBuffer [0x%p], dwOpBufferSize [%ld], hProtocol [0x%lx], pSP [0x%p]",
dwMsgId,pOpBuffer,dwOpBufferSize,hProtocol,pSP);
pRefCountBuffer = NULL;
pNTOp = NULL;
fReSync = FALSE;
//
// We will only need to worry about maintaining the operation list in PEER mode.
// Otherwise, just perform the operation
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
{
DWORD dwVersion;
DWORD dwVersionNotUsed;
BOOL fFound;
CBilink *pBilink;
CNameTableOp *pCurrent;
dwVersion = 0;
dwVersionNotUsed = 0;
//
// Get version of this operation
//
if ((hResultCode = DNNTGetOperationVersion( pdnObject,
dwMsgId,
pOpBuffer,
dwOpBufferSize,
&dwVersion,
&dwVersionNotUsed)) != DPN_OK)
{
DPFERR("Could not determine operation version");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
//
// Create NameTableOp
//
if ((hResultCode = NameTableOpNew(pdnObject,&pNTOp)) != DPN_OK)
{
DPFERR("Could not create NameTableOp");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
//
// Keep operation in a RefCountBuffer. If a protocol buffer was supplied (with handle)
// we will just release the buffer when we're done with it. Otherwise, we will need
// to copy the buffer supplied.
//
if (hProtocol)
{
if ((hResultCode = RefCountBufferNew(pdnObject,0,NULL,NULL,&pRefCountBuffer)) != DPN_OK)
{
DPFERR("Could not create RefCountBuffer");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
pRefCountBuffer->SetBufferDesc( static_cast<BYTE*>(pOpBuffer),
dwOpBufferSize,
DNFreeProtocolBuffer,
hProtocol);
}
else
{
if ((hResultCode = RefCountBufferNew(pdnObject,dwOpBufferSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
{
DPFERR("Could not create RefCountBuffer");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
memcpy(pRefCountBuffer->GetBufferAddress(),pOpBuffer,dwOpBufferSize);
}
pNTOp->SetMsgId(dwMsgId);
pNTOp->SetRefCountBuffer(pRefCountBuffer);
pNTOp->SetSP( pSP );
pNTOp->SetVersion(dwVersion);
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
//
// Insert into the NameTableOp list
//
fFound = FALSE;
pdnObject->NameTable.WriteLock();
pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
{
pCurrent = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
if (dwVersion < pCurrent->GetVersion())
{
pNTOp->m_bilinkNameTableOps.InsertBefore(&pCurrent->m_bilinkNameTableOps);
pCurrent = NULL;
fFound = TRUE;
break;
}
if (dwVersion == pCurrent->GetVersion())
{
//
// This is a NEWER operation which will replace the current operation in the list
//
pNTOp->m_bilinkNameTableOps.InsertBefore(&pCurrent->m_bilinkNameTableOps);
pCurrent->m_bilinkNameTableOps.RemoveFromList();
if (pCurrent->GetRefCountBuffer())
{
pCurrent->GetRefCountBuffer()->Release();
pCurrent->SetRefCountBuffer( NULL );
}
if (pCurrent->GetSP())
{
pCurrent->GetSP()->Release();
pCurrent->SetSP( NULL );
}
pCurrent->ReturnSelfToPool();
pCurrent = NULL;
fFound = TRUE;
break;
}
pCurrent = NULL;
pBilink = pBilink->GetNext();
}
if (!fFound)
{
pNTOp->m_bilinkNameTableOps.InsertBefore(&pdnObject->NameTable.m_bilinkNameTableOps);
}
pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
{
pCurrent = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
pBilink = pBilink->GetNext();
if (pCurrent->GetVersion() > pdnObject->NameTable.GetVersion())
{
DPFX(DPFPREP, 8,"Current [%ld], NameTable [%ld], InUse [%ld]",pCurrent->GetVersion(),
pdnObject->NameTable.GetVersion(),pCurrent->IsInUse());
if ((pCurrent->GetVersion() == (pdnObject->NameTable.GetVersion() + 1))
&& !pCurrent->IsInUse())
{
pCurrent->SetInUse();
if ((pCurrent->GetVersion() % DN_NAMETABLE_OP_RESYNC_INTERVAL) == 0)
{
fReSync = TRUE;
}
pdnObject->NameTable.Unlock();
hResultCode = DNNTPerformOperation( pdnObject,
pCurrent->GetMsgId(),
pCurrent->GetRefCountBuffer()->GetBufferAddress() );
pdnObject->NameTable.WriteLock();
}
else
{
//
// Once we find an operation that we won't perform, there is no point continuing
//
break;
}
}
}
//
// We will keep the operation buffer (if specified) so return DPNERR_PENDING
//
if (hProtocol)
{
hResultCode = DPNERR_PENDING;
}
else
{
hResultCode = DPN_OK;
}
pdnObject->NameTable.Unlock();
//
// Send a re-sync to the host if required
//
if (fReSync)
{
DPFX(DPFPREP, 5,"Send NameTable version re-sync to Host");
DNNTPlayerSendVersion(pdnObject);
}
}
else
{
DNNTPerformOperation(pdnObject,dwMsgId,pOpBuffer);
//
// We will not need to keep the operation buffer so return DPN_OK
//
hResultCode = DPN_OK;
}
Exit:
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return( hResultCode);
Failure:
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
if (pNTOp)
{
pNTOp->ReturnSelfToPool();
pNTOp = NULL;
}
goto Exit;
}
#else
{
HRESULT hResultCode;
CRefCountBuffer *pRefCountBuffer;
CNameTableOp *pNTOp;
DPFX(DPFPREP, 4,"Parameters: dwMsgId [0x%lx], pOpBuffer [0x%p], dwOpBufferSize [%ld], hProtocol [0x%lx], pSP [0x%p]",
dwMsgId,pOpBuffer,dwOpBufferSize,hProtocol,pSP);
pRefCountBuffer = NULL;
pNTOp = NULL;
//
// We will only need to worry about maintaining the operation list in PEER mode.
// Otherwise, just perform the operation
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
{
DWORD dwVersion;
DWORD dwVersionNotUsed;
dwVersion = 0;
dwVersionNotUsed = 0;
//
// Get version of this operation
//
if ((hResultCode = DNNTGetOperationVersion( pdnObject,
dwMsgId,
pOpBuffer,
dwOpBufferSize,
&dwVersion,
&dwVersionNotUsed)) != DPN_OK)
{
DPFERR("Could not determine operation version");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
//
// This operation will either need to be performed immediately (and then discarded), or queued
//
pdnObject->NameTable.WriteLock();
if (dwVersion == pdnObject->NameTable.GetVersion()+1)
{
CBilink *pBilink;
CNameTableOp *pCurrent;
pdnObject->NameTable.Unlock();
hResultCode = DNNTPerformOperation(pdnObject,dwMsgId,pOpBuffer);
//
// Perform any operations that are queued
//
pdnObject->NameTable.WriteLock();
pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
{
pCurrent = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
pBilink = pBilink->GetNext();
DPFX(DPFPREP, 8,"Current [%ld], NameTable [%ld], InUse [%ld]",pCurrent->GetVersion(),
pdnObject->NameTable.GetVersion(),pCurrent->IsInUse());
if ((pCurrent->GetVersion() == (pdnObject->NameTable.GetVersion() + 1))
&& !pCurrent->IsInUse())
{
pCurrent->SetInUse();
pdnObject->NameTable.Unlock();
hResultCode = DNNTPerformOperation( pdnObject,
pCurrent->GetMsgId(),
pCurrent->GetRefCountBuffer()->GetBufferAddress() );
pdnObject->NameTable.WriteLock();
//
// If we're not supporting host migration,
// we can discard operations as soon as they've been performed
//
pCurrent->m_bilinkNameTableOps.RemoveFromList();
if (pCurrent->GetRefCountBuffer())
{
pCurrent->GetRefCountBuffer()->Release();
pCurrent->SetRefCountBuffer( NULL );
}
if (pCurrent->GetSP())
{
pCurrent->GetSP()->Release();
pCurrent->SetSP( NULL );
}
pCurrent->ReturnSelfToPool();
}
else
{
//
// Once we find an operation that we won't perform, there is no point continuing
//
break;
}
}
pdnObject->NameTable.Unlock();
hResultCode = DPN_OK;
}
else
{
//
// Queue this operation for future execution
//
CNameTableOp *pCurrent;
CBilink *pBilink;
BOOL fFound;
//
// Create NameTableOp
//
if ((hResultCode = NameTableOpNew(pdnObject,&pNTOp)) != DPN_OK)
{
DPFERR("Could not create NameTableOp");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
//
// Keep operation in a RefCountBuffer. If a protocol buffer was supplied (with handle)
// we will just release the buffer when we're done with it. Otherwise, we will need
// to copy the buffer supplied.
//
if (hProtocol)
{
if ((hResultCode = RefCountBufferNew(pdnObject,0,NULL,NULL,&pRefCountBuffer)) != DPN_OK)
{
DPFERR("Could not create RefCountBuffer");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
pRefCountBuffer->SetBufferDesc( static_cast<BYTE*>(pOpBuffer),
dwOpBufferSize,
DNFreeProtocolBuffer,
hProtocol);
}
else
{
if ((hResultCode = RefCountBufferNew(pdnObject,dwOpBufferSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
{
DPFERR("Could not create RefCountBuffer");
DisplayDNError(0,hResultCode);
hResultCode = DPN_OK;
goto Failure;
}
memcpy(pRefCountBuffer->GetBufferAddress(),pOpBuffer,dwOpBufferSize);
}
pNTOp->SetMsgId(dwMsgId);
pNTOp->SetRefCountBuffer(pRefCountBuffer);
pNTOp->SetSP( pSP );
pNTOp->SetVersion(dwVersion);
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
//
// Insert into the NameTableOp list
//
fFound = FALSE;
// pdnObject->NameTable.WriteLock();
pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
{
pCurrent = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
if (dwVersion < pCurrent->GetVersion())
{
pNTOp->m_bilinkNameTableOps.InsertBefore(&pCurrent->m_bilinkNameTableOps);
pCurrent = NULL;
fFound = TRUE;
break;
}
if (dwVersion == pCurrent->GetVersion())
{
//
// This is a NEWER operation which will replace the current operation in the list
//
pNTOp->m_bilinkNameTableOps.InsertBefore(&pCurrent->m_bilinkNameTableOps);
pCurrent->m_bilinkNameTableOps.RemoveFromList();
if (pCurrent->GetRefCountBuffer())
{
pCurrent->GetRefCountBuffer()->Release();
pCurrent->SetRefCountBuffer( NULL );
}
if (pCurrent->GetSP())
{
pCurrent->GetSP()->Release();
pCurrent->SetSP( NULL );
}
pCurrent->ReturnSelfToPool();
pCurrent = NULL;
fFound = TRUE;
break;
}
pCurrent = NULL;
pBilink = pBilink->GetNext();
}
if (!fFound)
{
pNTOp->m_bilinkNameTableOps.InsertBefore(&pdnObject->NameTable.m_bilinkNameTableOps);
}
pdnObject->NameTable.Unlock();
hResultCode = DPNERR_PENDING;
}
}
else
{
DNNTPerformOperation(pdnObject,dwMsgId,pOpBuffer);
//
// We will not need to keep the operation buffer so return DPN_OK
//
hResultCode = DPN_OK;
}
Exit:
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return( hResultCode);
Failure:
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
if (pNTOp)
{
pNTOp->ReturnSelfToPool();
pNTOp = NULL;
}
goto Exit;
}
#endif // DPNBUILD_NOHOSTMIGRATE
// DNNTFindOperation
//
// Find a NameTable Operation
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTFindOperation"
HRESULT DNNTFindOperation(DIRECTNETOBJECT *const pdnObject,
const DWORD dwVersion,
CNameTableOp **ppNTOp)
{
HRESULT hResultCode;
CBilink *pBilink;
CNameTableOp *pNTOp;
DPFX(DPFPREP, 6,"Parameters: dwVersion [%ld = 0x%lx], ppNTOp [0x%p]",dwVersion,dwVersion,ppNTOp);
DNASSERT(ppNTOp != NULL);
hResultCode = DPNERR_DOESNOTEXIST;
pdnObject->NameTable.ReadLock();
pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
{
pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
if (pNTOp->GetVersion() == dwVersion)
{
*ppNTOp = pNTOp;
hResultCode = DPN_OK;
break;
}
else if (pNTOp->GetVersion() > dwVersion)
{
//
// Passed where it could have been, so there is no point in continuing
//
break;
}
pBilink = pBilink->GetNext();
}
pdnObject->NameTable.Unlock();
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DNNTRemoveOperations
//
// Remove NameTable Operations
#undef DPF_MODNAME
#define DPF_MODNAME "DNNTRemoveOperations"
void DNNTRemoveOperations(DIRECTNETOBJECT *const pdnObject,
const DWORD dwOldestVersion,
const BOOL fRemoveAll)
{
CBilink *pBilink;
CNameTableOp *pNTOp;
DPFX(DPFPREP, 4,"Parameters: dwOldestVersion [%ld = 0x%lx], fRemoveAll [%ld]",dwOldestVersion,dwOldestVersion,fRemoveAll);
DNASSERT(pdnObject != NULL);
pdnObject->NameTable.WriteLock();
pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
{
pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
pBilink = pBilink->GetNext();
if (fRemoveAll || (pNTOp->GetVersion() < dwOldestVersion))
{
pNTOp->m_bilinkNameTableOps.RemoveFromList();
if (pNTOp->GetRefCountBuffer())
{
pNTOp->GetRefCountBuffer()->Release();
pNTOp->SetRefCountBuffer( NULL );
}
if (pNTOp->GetSP())
{
pNTOp->GetSP()->Release();
pNTOp->SetSP( NULL );
}
pNTOp->ReturnSelfToPool();
}
}
pdnObject->NameTable.Unlock();
DPFX(DPFPREP, 4,"Returning");
}