/*========================================================================== * * 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(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(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(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(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(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(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(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(pRequest + 1); if (pCreateGroup->dwNameSize) { pwszName = reinterpret_cast(reinterpret_cast(pCreateGroup) + pCreateGroup->dwNameOffset); } else { pwszName = NULL; } if (pCreateGroup->dwDataSize) { pvData = static_cast(reinterpret_cast(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(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(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(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(pRequest + 1); if (pUpdateInfo->dwNameSize) { pwszName = reinterpret_cast(reinterpret_cast(pUpdateInfo) + pUpdateInfo->dwNameOffset); } else { pwszName = NULL; } if (pUpdateInfo->dwDataSize) { pvData = reinterpret_cast(reinterpret_cast(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(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(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(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(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(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(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(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(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(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(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(pvBuffer); pInfo = reinterpret_cast(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(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(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(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(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(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(static_cast(pvBuffer) + pMsg->dwNameOffset); } else { pwszName = NULL; } if ((pMsg->dwInfoFlags & DPNINFO_DATA) && (pMsg->dwDataOffset)) { pvData = static_cast(static_cast(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(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(pRefCountBuffer->GetBufferAddress()); pMsg = static_cast(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; }