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

821 lines
20 KiB

/*==========================================================================
*
* 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");
}