|
|
/*==========================================================================
* * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved. * * File: NTEntry.cpp * Content: NameTable Entry Objects *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 03/10/00 mjn Created * 04/06/00 mjn Added AvailableEvent to block pre-ADD_PLAYER-notification sends * 05/05/00 mjn Added GetConnectionRef() * 05/16/00 mjn Better locking during User notifications * 06/27/00 rmt Added COM abstraction * 07/22/00 mjn Pack/Unpack DNET version in DN_NAMETABLE_ENTRY_INFO * 07/26/00 mjn Fix PackInfo() to handle NULL names and data * 08/03/00 rmt Bug #41386 - Getting player info when no name and/or user data returns garbage in * name / data field. * 09/06/00 mjn Changed SetAddress() to return void instead of HRESULT * 09/13/00 mjn Added PerformQueuedOperations() * 09/17/00 mjn Added NotifyAddRef() and NotifyRelease() * 09/28/00 mjn Flag AutoDestruct groups in PackInfo() * 10/11/00 mjn Don't take locks in PackInfo() * 01/25/01 mjn Fixed 64-bit alignment problem when unpacking entries * 04/19/01 mjn Lock entry when packing in PackEntryInfo() * 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
//**********************************************************************
void CNameTableEntry::ReturnSelfToPool( void ) { g_NameTableEntryPool.Release( this ); };
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::Release"
void CNameTableEntry::Release(void) { LONG lRefCount;
DNASSERT(m_lRefCount > 0); lRefCount = DNInterlockedDecrement(const_cast<LONG*>(&m_lRefCount)); DPFX(DPFPREP, 3,"NameTableEntry::Release [0x%p] RefCount [0x%lx]",this,lRefCount); if (lRefCount == 0) { DNASSERT(!(m_dwFlags & NAMETABLE_ENTRY_FLAG_AVAILABLE));
DNASSERT(m_bilinkDeleted.IsEmpty()); DNASSERT(m_bilinkMembership.IsEmpty()); DNASSERT(m_bilinkConnections.IsEmpty()); DNASSERT(m_bilinkQueuedMsgs.IsEmpty());
if (m_pAddress) { IDirectPlay8Address_Release(m_pAddress); m_pAddress = NULL; } if (m_pConnection) { m_pConnection->Release(); m_pConnection = NULL; } if (m_pwszName) { DNFree(m_pwszName); m_pwszName = NULL; } if (m_pvData) { DNFree(m_pvData); m_pvData = NULL; m_dwDataSize = 0; } m_dwFlags = 0; m_lRefCount = 0; ReturnSelfToPool(); } }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::NotifyAddRef"
void CNameTableEntry::NotifyAddRef( void ) { LONG lRefCount;
lRefCount = DNInterlockedIncrement( const_cast<LONG*>(&m_lNotifyRefCount) ); DNASSERT( lRefCount >= 0 ); }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::NotifyRelease"
void CNameTableEntry::NotifyRelease( void ) { LONG lRefCount;
lRefCount = DNInterlockedDecrement( const_cast<LONG*>(&m_lNotifyRefCount) ); DNASSERT( lRefCount >= 0 );
if (lRefCount == 0) { Lock(); // DNASSERT(IsDisconnecting());
if (IsNeedToDestroy()) { Unlock();
//
// Generate notifications
//
if (IsGroup()) { if (!IsAllPlayersGroup()) { DNUserDestroyGroup(m_pdnObject,this); } } else { if (IsIndicated() && !IsCreated()) { DNUserIndicatedConnectAborted(m_pdnObject,m_pvContext); } else { DNASSERT(IsCreated()); DNUserDestroyPlayer(m_pdnObject,this); } }
m_pdnObject->NameTable.WriteLock(); Lock(); m_bilinkDeleted.RemoveFromList(); m_pdnObject->NameTable.Unlock(); ClearNeedToDestroy(); ClearCreated(); } Unlock(); } }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::UpdateEntryInfo"
HRESULT CNameTableEntry::UpdateEntryInfo(UNALIGNED WCHAR *const pwszName, const DWORD dwNameSize, void *const pvData, const DWORD dwDataSize, const DWORD dwInfoFlags, BOOL fNotify) { PWSTR pwszTempName; DWORD dwTempNameSize; void *pvTempData; DWORD dwTempDataSize;
Lock();
if (dwInfoFlags & DPNINFO_NAME) { if (pwszName && dwNameSize) { if ((pwszTempName = static_cast<WCHAR*>(DNMalloc(dwNameSize))) == NULL) { return(DPNERR_OUTOFMEMORY); } memcpy(pwszTempName,pwszName,dwNameSize); dwTempNameSize = dwNameSize; } else { pwszTempName = NULL; dwTempNameSize = 0; } if (m_pwszName) { DNFree(m_pwszName); } m_pwszName = pwszTempName; m_dwNameSize = dwTempNameSize; } if (dwInfoFlags & DPNINFO_DATA) { if (pvData && dwDataSize) { if ((pvTempData = DNMalloc(dwDataSize)) == NULL) { return(DPNERR_OUTOFMEMORY); } memcpy(pvTempData,pvData,dwDataSize); dwTempDataSize = dwDataSize; } else { pvTempData = NULL; dwTempDataSize = 0; } if (m_pvData) { DNFree(m_pvData); } m_pvData = pvTempData; m_dwDataSize = dwTempDataSize; }
// Generate notifications
if (m_dwFlags & NAMETABLE_ENTRY_FLAG_AVAILABLE && fNotify) { DPNID dpnid = m_dpnid; PVOID pvContext = m_pvContext; DIRECTNETOBJECT* pdnObject = m_pdnObject;
if (m_dwFlags & NAMETABLE_ENTRY_FLAG_GROUP) { Unlock(); DNUserUpdateGroupInfo(pdnObject,dpnid,pvContext); } else { if (m_dwFlags & NAMETABLE_ENTRY_FLAG_PEER) { Unlock(); DNUserUpdatePeerInfo(pdnObject,dpnid,pvContext); } #ifndef DPNBUILD_NOSERVER
else if (m_dwFlags & NAMETABLE_ENTRY_FLAG_CLIENT && pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) { Unlock(); DNUserUpdateClientInfo(pdnObject,dpnid,pvContext); } #endif // DPNBUILD_NOSERVER
else if (m_dwFlags & NAMETABLE_ENTRY_FLAG_SERVER && pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT) { Unlock(); // Clients do not get to see server's DPNID or context
DNUserUpdateServerInfo(pdnObject,0,0); } else { Unlock(); DNASSERT(FALSE); } } } else { Unlock(); }
return(DPN_OK); }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::SetAddress"
void CNameTableEntry::SetAddress( IDirectPlay8Address *const pAddress ) { if (pAddress) { IDirectPlay8Address_AddRef(pAddress); }
if (m_pAddress) { IDirectPlay8Address_Release(m_pAddress); m_pAddress = NULL; } m_pAddress = pAddress; }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::SetConnection"
void CNameTableEntry::SetConnection( CConnection *const pConnection ) { if (pConnection) { pConnection->AddRef(); } m_pConnection = pConnection; }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::GetConnectionRef"
HRESULT CNameTableEntry::GetConnectionRef( CConnection **const ppConnection ) { HRESULT hResultCode;
DNASSERT( ppConnection != NULL);
Lock(); if ( m_pConnection && !m_pConnection->IsInvalid()) { m_pConnection->AddRef(); *ppConnection = m_pConnection; hResultCode = DPN_OK; } else { hResultCode = DPNERR_NOCONNECTION; } Unlock();
return( hResultCode ); }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::PackInfo"
HRESULT CNameTableEntry::PackInfo(CPackedBuffer *const pPackedBuffer) { HRESULT hResultCode; DPN_PLAYER_INFO *pPlayerInfo; DPN_GROUP_INFO *pGroupInfo;
DNASSERT(pPackedBuffer != NULL);
// Lock();
if (m_dwFlags & NAMETABLE_ENTRY_FLAG_GROUP) { pGroupInfo = static_cast<DPN_GROUP_INFO*>(pPackedBuffer->GetHeadAddress()); hResultCode = pPackedBuffer->AddToFront(NULL,sizeof(DPN_GROUP_INFO)); //
// Add data
//
if ((m_pvData) && (m_dwDataSize != 0)) { if ((hResultCode = pPackedBuffer->AddToBack(m_pvData,m_dwDataSize)) == DPN_OK) { pGroupInfo->pvData = pPackedBuffer->GetTailAddress(); pGroupInfo->dwDataSize = m_dwDataSize; } } else { if (pGroupInfo) { pGroupInfo->pvData = NULL; pGroupInfo->dwDataSize = 0; } }
//
// Add name
//
if ((m_pwszName) && (m_dwNameSize != 0)) { if ((hResultCode = pPackedBuffer->AddToBack(m_pwszName,m_dwNameSize)) == DPN_OK) { pGroupInfo->pwszName = static_cast<WCHAR*>(pPackedBuffer->GetTailAddress()); } } else { if (pGroupInfo) { pGroupInfo->pwszName = NULL; } }
//
// Update flags
//
if (hResultCode == DPN_OK) { if (pGroupInfo) { pGroupInfo->dwSize = sizeof(DPN_GROUP_INFO); pGroupInfo->dwInfoFlags = DPNINFO_NAME | DPNINFO_DATA; pGroupInfo->dwGroupFlags = 0; if (IsAutoDestructGroup()) { pGroupInfo->dwGroupFlags |= DPNGROUP_AUTODESTRUCT; } } } } else { pPlayerInfo = static_cast<DPN_PLAYER_INFO*>(pPackedBuffer->GetHeadAddress()); hResultCode = pPackedBuffer->AddToFront(NULL,sizeof(DPN_PLAYER_INFO));
if( !m_dwDataSize ) { if( pPlayerInfo ) { pPlayerInfo->pvData = NULL; pPlayerInfo->dwDataSize = 0; } } else { if ((hResultCode = pPackedBuffer->AddToBack(m_pvData,m_dwDataSize)) == DPN_OK) { pPlayerInfo->pvData = pPackedBuffer->GetTailAddress(); pPlayerInfo->dwDataSize = m_dwDataSize; } }
if( !m_pwszName ) { if( pPlayerInfo ) { pPlayerInfo->pwszName = NULL; } } else { if ((hResultCode = pPackedBuffer->AddToBack(m_pwszName,m_dwNameSize)) == DPN_OK) { pPlayerInfo->pwszName = static_cast<WCHAR*>(pPackedBuffer->GetTailAddress()); } } if (hResultCode == DPN_OK) { pPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); pPlayerInfo->dwInfoFlags = DPNINFO_NAME | DPNINFO_DATA; pPlayerInfo->dwPlayerFlags = 0; if (m_dwFlags & NAMETABLE_ENTRY_FLAG_HOST) { pPlayerInfo->dwPlayerFlags |= DPNPLAYER_HOST; } if (m_dwFlags & NAMETABLE_ENTRY_FLAG_LOCAL) { pPlayerInfo->dwPlayerFlags |= DPNPLAYER_LOCAL; } } } // Unlock();
return(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::PackEntryInfo"
HRESULT CNameTableEntry::PackEntryInfo(CPackedBuffer *const pPackedBuffer) { DWORD dwURLSize; HRESULT hResultCode; DN_NAMETABLE_ENTRY_INFO dnEntryInfo;
DPFX(DPFPREP, 6,"Attempting to pack [0x%lx]",m_dpnid);
DNASSERT(pPackedBuffer != NULL);
Lock();
dnEntryInfo.dpnid = m_dpnid; dnEntryInfo.dpnidOwner = m_dpnidOwner; dnEntryInfo.dwFlags = m_dwFlags & ( NAMETABLE_ENTRY_FLAG_HOST | NAMETABLE_ENTRY_FLAG_ALL_PLAYERS_GROUP | NAMETABLE_ENTRY_FLAG_GROUP | NAMETABLE_ENTRY_FLAG_GROUP_AUTODESTRUCT | NAMETABLE_ENTRY_FLAG_PEER | NAMETABLE_ENTRY_FLAG_CLIENT | NAMETABLE_ENTRY_FLAG_SERVER ); dnEntryInfo.dwVersion = m_dwVersion; dnEntryInfo.dwVersionNotUsed = m_dwVersionNotUsed; dnEntryInfo.dwDNETVersion = m_dwDNETVersion;
// Entry name
if (m_pwszName != NULL) { if ((hResultCode = pPackedBuffer->AddToBack(m_pwszName,m_dwNameSize)) == DPN_OK) { dnEntryInfo.dwNameOffset = pPackedBuffer->GetTailOffset(); dnEntryInfo.dwNameSize = m_dwNameSize; } } else { dnEntryInfo.dwNameOffset = 0; dnEntryInfo.dwNameSize = 0; }
// Entry data
if (m_pvData != NULL && m_dwDataSize != 0) { if ((hResultCode = pPackedBuffer->AddToBack(m_pvData,m_dwDataSize)) == DPN_OK) { dnEntryInfo.dwDataOffset = pPackedBuffer->GetTailOffset(); dnEntryInfo.dwDataSize = m_dwDataSize; } } else { dnEntryInfo.dwDataOffset = 0; dnEntryInfo.dwDataSize = 0; }
// Entry address (URL)
if ((m_pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) && (m_pAddress != NULL)) { dwURLSize = 0; hResultCode = IDirectPlay8Address_GetURLA(m_pAddress,NULL,&dwURLSize); if (hResultCode != DPN_OK && hResultCode != DPNERR_BUFFERTOOSMALL) { DPFERR("Could not determine URL size"); DisplayDNError(0,hResultCode); Unlock(); goto EXIT_PackEntry; } if (dwURLSize != 0) { if ((hResultCode = pPackedBuffer->AddToBack(NULL,dwURLSize)) == DPN_OK) { if ((hResultCode = IDirectPlay8Address_GetURLA(m_pAddress, static_cast<char*>(pPackedBuffer->GetTailAddress()),&dwURLSize)) == DPN_OK) { dnEntryInfo.dwURLOffset = pPackedBuffer->GetTailOffset(); dnEntryInfo.dwURLSize = dwURLSize; } else { DPFERR("Could not extract URL from DirectPlayAddress"); DisplayDNError(0,hResultCode); Unlock(); goto EXIT_PackEntry; } } } else { dnEntryInfo.dwURLOffset = 0; dnEntryInfo.dwURLSize = 0; } } else { dnEntryInfo.dwURLOffset = 0; dnEntryInfo.dwURLSize = 0; }
hResultCode = pPackedBuffer->AddToFront(&dnEntryInfo,sizeof(DN_NAMETABLE_ENTRY_INFO));
Unlock();
EXIT_PackEntry:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::UnpackEntryInfo"
HRESULT CNameTableEntry::UnpackEntryInfo(UNALIGNED const DN_NAMETABLE_ENTRY_INFO *const pdnEntryInfo, BYTE *const pBufferStart) { HRESULT hResultCode; PWSTR pwszName; DWORD dwNameSize; void *pvData; DWORD dwDataSize; IDirectPlay8Address *pAddress;
DNASSERT(m_pwszName == NULL); DNASSERT(m_pvData == NULL); DNASSERT(m_pAddress == NULL);
if (pdnEntryInfo->dwNameOffset && pdnEntryInfo->dwNameSize) { pwszName = reinterpret_cast<WCHAR*>(pBufferStart + pdnEntryInfo->dwNameOffset); dwNameSize = pdnEntryInfo->dwNameSize; } else { pwszName = NULL; dwNameSize = 0; }
if (pdnEntryInfo->dwDataOffset && pdnEntryInfo->dwDataSize) { pvData = static_cast<void*>(pBufferStart + pdnEntryInfo->dwDataOffset); dwDataSize = pdnEntryInfo->dwDataSize; } else { pvData = NULL; dwDataSize = 0; }
// This function takes the lock internally
UpdateEntryInfo(pwszName,dwNameSize,pvData,dwDataSize,DPNINFO_NAME|DPNINFO_DATA, FALSE);
pAddress = NULL; if (pdnEntryInfo->dwURLOffset) { #ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address, reinterpret_cast<void**>(&pAddress)); #else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>(&pAddress), FALSE); #endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK) { DPFERR("Could not create empty DirectPlayAddress"); DisplayDNError(0,hResultCode); return(DPNERR_OUTOFMEMORY); } hResultCode = IDirectPlay8Address_BuildFromURLA(pAddress,reinterpret_cast<char*>(pBufferStart + pdnEntryInfo->dwURLOffset)); if (hResultCode != DPN_OK) { DPFERR("Could not build URL"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); IDirectPlay8Address_Release(pAddress); pAddress = NULL; return(hResultCode); } SetAddress(pAddress); IDirectPlay8Address_Release(pAddress); pAddress = NULL; }
m_dpnid = pdnEntryInfo->dpnid; m_dpnidOwner = pdnEntryInfo->dpnidOwner; m_dwFlags = pdnEntryInfo->dwFlags; m_dwDNETVersion = pdnEntryInfo->dwDNETVersion; m_dwVersion = pdnEntryInfo->dwVersion; m_dwVersionNotUsed = pdnEntryInfo->dwVersionNotUsed;
return(DPN_OK); }
#undef DPF_MODNAME
#define DPF_MODNAME "CNameTableEntry::PerformQueuedOperations"
void CNameTableEntry::PerformQueuedOperations( void ) { HRESULT hResultCode; CQueuedMsg *pQueuedMsg; BOOL fDestroy;
DPFX(DPFPREP, 6,"Parameters: (none)");
fDestroy = FALSE;
Lock(); fDestroy = IsNeedToDestroy();
//
// This assumes that the InUse flag is set. We will clear it before returning.
//
#ifdef DBG
DNASSERT( IsInUse() );
if (!m_bilinkQueuedMsgs.IsEmpty()) { DPFX(DPFPREP, 7, "Nametable entry 0x%p has %i queued messages.", this, m_lNumQueuedMsgs); } #endif // DBG
while (!m_bilinkQueuedMsgs.IsEmpty()) { pQueuedMsg = CONTAINING_OBJECT(m_bilinkQueuedMsgs.GetNext(),CQueuedMsg,m_bilinkQueuedMsgs); pQueuedMsg->m_bilinkQueuedMsgs.RemoveFromList(); DEBUG_ONLY(m_lNumQueuedMsgs--);
Unlock();
switch (pQueuedMsg->GetOpType()) { case RECEIVE: { HRESULT hrProcess;
DNASSERT(pQueuedMsg->GetAsyncOp() != NULL); DNASSERT(pQueuedMsg->GetAsyncOp()->GetHandle() != 0);
#ifndef DPNBUILD_NOVOICE
if (pQueuedMsg->IsVoiceMessage()) { hrProcess = Voice_Receive( m_pdnObject, GetDPNID(), 0, pQueuedMsg->GetBuffer(), pQueuedMsg->GetBufferSize());
NotifyRelease();
} else #endif // DPNBUILD_NOVOICE
{ hrProcess = DNUserReceive( m_pdnObject, this, pQueuedMsg->GetBuffer(), pQueuedMsg->GetBufferSize(), pQueuedMsg->GetAsyncOp()->GetHandle()); if (pQueuedMsg->GetCompletionOp() != 0) { //
// Send completion message
//
CConnection *pConnection;
pConnection = NULL; if ((hResultCode = GetConnectionRef( &pConnection )) == DPN_OK) { hResultCode = DNSendUserProcessCompletion( m_pdnObject, pConnection, pQueuedMsg->GetCompletionOp()); } pConnection->Release(); pConnection = NULL; } }
//
// See if we can return this buffer now
//
if (hrProcess == DPNERR_PENDING) { pQueuedMsg->GetAsyncOp()->Release(); pQueuedMsg->SetAsyncOp( NULL ); } else { DNEnterCriticalSection(&m_pdnObject->csActiveList); pQueuedMsg->GetAsyncOp()->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&m_pdnObject->csActiveList); pQueuedMsg->GetAsyncOp()->Lock(); if (!pQueuedMsg->GetAsyncOp()->IsCancelled() && !pQueuedMsg->GetAsyncOp()->IsComplete()) { pQueuedMsg->GetAsyncOp()->SetComplete(); pQueuedMsg->GetAsyncOp()->Unlock(); if (SUCCEEDED(m_pdnObject->HandleTable.Destroy( pQueuedMsg->GetAsyncOp()->GetHandle(), NULL ))) { // Release the HandleTable reference
pQueuedMsg->GetAsyncOp()->Release(); } } else { pQueuedMsg->GetAsyncOp()->Unlock(); } pQueuedMsg->GetAsyncOp()->Release(); pQueuedMsg->SetAsyncOp( NULL ); }
break; } default: { DPFERR("Invalid Queued Operation"); DNASSERT(FALSE); break; } }
//
// Return this queued message
//
pQueuedMsg->ReturnSelfToPool(); pQueuedMsg = NULL;
Lock(); fDestroy = IsNeedToDestroy(); }
//
// No longer processing
//
ClearInUse(); Unlock();
DPFX(DPFPREP, 6,"Returning"); }
|