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.
 
 
 
 
 
 

511 lines
13 KiB

//+----------------------------------------------------------------------------
//
// Copyright (C) 2001, Microsoft Corporation
//
// File: DfsSiteCache.cxx
//
// Contents: implements the base DFS Site hash class
//
//
// History: July. 10 2001, Author: Rohanp
//
//-----------------------------------------------------------------------------
#include "dfsgeneric.hxx"
#include "dfsinit.hxx"
#include "dsgetdc.h"
#include "lm.h"
#include <winsock2.h>
#include "DfsSiteCache.hxx"
#include <DfsSite.hxx>
#include "DfsSiteCache.tmh"
void *
AllocateSitecacheData(ULONG Size )
{
PVOID RetValue = NULL;
if (Size)
{
RetValue = (PVOID) new BYTE[Size];
if(RetValue != NULL)
{
RtlZeroMemory( RetValue, Size );
}
}
return RetValue;
}
DFSSTATUS
DfsSiteNameCache::DfsInitializeSiteCache(void)
{
DFSSTATUS Status = ERROR_SUCCESS;
SHASH_FUNCTABLE FunctionTable;
ZeroMemory(&FunctionTable, sizeof(FunctionTable));
FunctionTable.CompareFunc = CompareSiteIpAddress;
FunctionTable.HashFunc = DfsHashIpAddress;
FunctionTable.AllocFunc = AllocateSitecacheData;
FunctionTable.FreeFunc = DfsDeallocateHashData;
FunctionTable.AllocHashEntryFunc = AllocateSitecacheData;
FunctionTable.FreeHashEntryFunc = DeallocateSiteCacheData;
Status = ShashInitHashTable(&pSiteTable, &FunctionTable);
Status = RtlNtStatusToDosError(Status);
return Status;
}
DfsSiteNameCache *
DfsSiteNameCache::CreateSiteHashTable(DFSSTATUS * pStatus)
{
DfsSiteNameCache * pSiteTable = NULL;
DFSSTATUS Status = ERROR_SUCCESS;
pSiteTable = new DfsSiteNameCache(&Status);
if(pSiteTable == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
Status = pSiteTable->DfsInitializeSiteCache();
if(Status != ERROR_SUCCESS)
{
delete pSiteTable;
pSiteTable = NULL;
}
}
*pStatus = Status;
return pSiteTable;
}
DFSSTATUS
DfsSiteNameCache::CreateSiteData(
IN DWORD IpAddress,
IN DfsSite *pNewSite,
OUT PDFSSITE_DATA *ppSiteData )
{
PDFSSITE_DATA SiteStructure = NULL;
DFSSTATUS Status = ERROR_SUCCESS;
*ppSiteData = NULL;
do {
SiteStructure = (PDFSSITE_DATA) AllocateSitecacheData(sizeof( DFSSITE_DATA ));
if (SiteStructure == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
break;
}
RtlZeroMemory(SiteStructure, sizeof(DFSSITE_DATA));
SiteStructure->Header.RefCount = 1;
SiteStructure->Header.pvKey = (PVOID) (ULONG_PTR)IpAddress;
SiteStructure->Header.pData = (PVOID)SiteStructure;
SiteStructure->FirstAccessTime = GetTickCount();
SiteStructure->InMruList = FALSE;
SiteStructure->Accessed = SITE_ACCESSED;
SiteStructure->IpAddress = IpAddress;
//
// Now attach a referenced ClientSite.
//
pNewSite->AcquireReference();
SiteStructure->ClientSite = pNewSite;
*ppSiteData = SiteStructure;
} while (FALSE);
//
// We haven't added this to the table yet.
// So, just free the whole thing in case of error.
// This will release the DfsSite as well, if it's initialized.
//
if (Status != ERROR_SUCCESS && SiteStructure != NULL)
{
DeallocateSiteCacheData( SiteStructure );
*ppSiteData = NULL;
}
return Status;
}
DFSSTATUS
DfsSiteNameCache::InsertInMruList(PDFSSITE_DATA SiteStructure)
{
DFSSTATUS Status = ERROR_SUCCESS;
EnterCriticalSection(&m_Lock);
SiteStructure->InMruList = TRUE;
InsertHeadList( &MruList, &SiteStructure->ListEntry ) ;
LeaveCriticalSection(&m_Lock);
return Status;
}
DFSSTATUS
DfsSiteNameCache::RemoveFromMruList(PDFSSITE_DATA pSiteStructure)
{
DFSSTATUS Status = ERROR_SUCCESS;
EnterCriticalSection(&m_Lock);
if(pSiteStructure->InMruList == TRUE)
{
RemoveEntryList( &pSiteStructure->ListEntry ) ;
pSiteStructure->InMruList = FALSE ;
ReleaseSiteCacheData(pSiteStructure);
}
LeaveCriticalSection(&m_Lock);
return Status;
}
DFSSTATUS
DfsSiteNameCache::MoveToFrontOfMruList(PDFSSITE_DATA pSiteStructure)
{
DFSSTATUS Status = ERROR_SUCCESS;
EnterCriticalSection(&m_Lock);
if(pSiteStructure->InMruList == TRUE)
{
RemoveEntryList( &pSiteStructure->ListEntry ) ;
InsertHeadList( &MruList, &pSiteStructure->ListEntry ) ;
InterlockedExchange(&pSiteStructure->Accessed,
SITE_ACCESSED);
}
LeaveCriticalSection(&m_Lock);
return Status;
}
DFSSTATUS
DfsSiteNameCache::StoreSiteInCache(
DWORD IpAddress,
DfsSite *pSite,
BOOLEAN IsRefresh)
{
PDFSSITE_DATA SiteStructure = NULL;
NTSTATUS NtStatus = STATUS_SUCCESS;
DFSSTATUS Status = ERROR_SUCCESS;
LONG CurrentSiteEntries = 0;
//assume success first. Also, if an existing entry is inthe cache, and we are
//just replacing it (IsRefresh == TRUE), then don't bump the count.
if(IsRefresh == FALSE)
{
CurrentSiteEntries = InterlockedIncrement( &DfsServerGlobalData.NumClientDfsSiteEntries );
if(CurrentSiteEntries >
DfsServerGlobalData.NumClientSiteEntriesAllowed)
{
InterlockedDecrement( &DfsServerGlobalData.NumClientDfsSiteEntries );
Status = ERROR_REMOTE_SESSION_LIMIT_EXCEEDED;
return Status;
}
}
Status = CreateSiteData( IpAddress,
pSite,
&SiteStructure );
if (Status == ERROR_SUCCESS)
{
if(IsRefresh)
{
SiteStructure->Accessed = SITE_NOTACCESSED;
}
NtStatus = SHashInsertKey(pSiteTable,
SiteStructure,
(void *) (ULONG_PTR)IpAddress,
SHASH_REPLACE_IFFOUND);
if(NtStatus == STATUS_SUCCESS)
{
if(InsertInMruList(SiteStructure) != ERROR_SUCCESS)
{
InterlockedDecrement(&SiteStructure->Header.RefCount);
}
// for stats
DFS_TRACE_LOW( SITE, "Added Site %ws to IPCache (IP %x)\n",
pSite->SiteNameString(), IpAddress);
}
else
{
DeallocateSiteCacheData( SiteStructure );
Status = RtlNtStatusToDosError(NtStatus);
}
}
if((NtStatus != STATUS_SUCCESS) && (IsRefresh == FALSE))
{
InterlockedDecrement( &DfsServerGlobalData.NumClientDfsSiteEntries );
}
return Status;
}
PSHASH_HEADER
DfsSiteNameCache::LookupIpInHash(DWORD IpAddress)
{
DFSSTATUS Status = ERROR_SUCCESS;
PSHASH_HEADER pHeader = NULL;
PDFSSITE_DATA pSiteStructure = NULL;
pHeader = SHashLookupKeyEx(pSiteTable,
(void *) (ULONG_PTR) IpAddress);
if(pHeader != NULL)
{
pSiteStructure = (PDFSSITE_DATA) pHeader;
MoveToFrontOfMruList(pSiteStructure);
}
return pHeader;
}
void
DfsSiteNameCache::
ReleaseSiteCacheData(PDFSSITE_DATA pData)
{
SHashReleaseReference(pSiteTable,
(PSHASH_HEADER) pData );
}
BOOLEAN
DfsSiteNameCache::IsTimeToRefresh(PDFSSITE_DATA pSiteData)
{
DWORD TimeNow = 0;
TimeNow = GetTickCount();
if ((TimeNow > pSiteData->FirstAccessTime) &&
(TimeNow - pSiteData->FirstAccessTime) > DfsServerGlobalData.SiteSupportRefreshInterval)
{
return TRUE;
}
if ((TimeNow < pSiteData->FirstAccessTime) &&
((TimeNow - 0) + (0xFFFFFFFF - pSiteData->FirstAccessTime) > DfsServerGlobalData.SiteSupportRefreshInterval))
{
return TRUE;
}
return FALSE;
}
DFSSTATUS
DfsSiteNameCache::ResetSiteData(PDFSSITE_DATA pExistingData)
{
DFSSTATUS Status = ERROR_SUCCESS;
DfsSite *pClientSite = NULL;
unsigned char *IpAddr = (unsigned char *) &(pExistingData->IpAddress);
DFS_TRACE_LOW( SITE, "ResetSiteData: old Site %ws, IP %d:%d:%d:%d\n",
pExistingData->ClientSite->SiteNameString(), IpAddr[0],
IpAddr[1],
IpAddr[2],
IpAddr[3]);
//
// Find a new DfsSite for it. This will do the DsGetSiteName calls
// again.
//
DfsIpToDfsSite((char *) (ULONG_PTR)&pExistingData->IpAddress,
4,
AF_INET,
&pClientSite);
ASSERT( pClientSite != NULL );
Status = StoreSiteInCache( pExistingData->IpAddress,
pClientSite,
TRUE);
//
// Release the reference we got (above in DfsIpToDfsSite).
// The cache has already taken the reference it needs in CreateSiteData.
//
pClientSite->ReleaseReference();
DFS_TRACE_LOW( SITE, "ResetSiteData: new Site %ws, IP %d:%d:%d:%d\n",
pExistingData->ClientSite->SiteNameString(), IpAddr[0],
IpAddr[1],
IpAddr[2],
IpAddr[3]);
return Status;
}
DFSSTATUS
DfsSiteNameCache::DeleteSiteData(PDFSSITE_DATA pSiteStructure)
{
DFSSTATUS Status = ERROR_SUCCESS;
SHashMarkForDeletion(pSiteTable, (PSHASH_HEADER) pSiteStructure);
return Status;
}
DFSSTATUS
DfsSiteNameCache::RemoveAndDeleteSiteData(PDFSSITE_DATA pExistingData)
{
DFSSTATUS Status = ERROR_SUCCESS;
unsigned char *IpAddr = (unsigned char *) &(pExistingData->IpAddress);
DFS_TRACE_LOW( SITE, "RemoveAndDeleteSiteData: old Site %ws, IP %d:%d:%d:%d\n",
pExistingData->ClientSite->SiteNameString(), IpAddr[0],
IpAddr[1],
IpAddr[2],
IpAddr[3]);
Status = RemoveFromMruList(pExistingData);
if(Status == STATUS_SUCCESS)
{
Status = DeleteSiteData(pExistingData);
}
if(Status == ERROR_SUCCESS)
{
InterlockedDecrement( &DfsServerGlobalData.NumClientDfsSiteEntries );
}
return Status;
}
DFSSTATUS
DfsSiteNameCache::RefreshSiteData(void)
{
DFSSTATUS Status = ERROR_SUCCESS;
BOOLEAN TimeToRefresh = FALSE;
BOOLEAN WasAccessed = FALSE;
LPWSTR *SiteNamesArray = NULL;
PDFSSITE_DATA pExistingData = NULL;
SHASH_ITERATOR Iter;
pExistingData = (PDFSSITE_DATA) SHashStartEnumerate(&Iter, pSiteTable);
while ((pExistingData != NULL) &&
(!DfsIsShuttingDown()))
{
WasAccessed = ResetSiteAccessMask(pExistingData);
if(WasAccessed)
{
TimeToRefresh = IsTimeToRefresh(pExistingData);
if(TimeToRefresh == TRUE)
{
Status = RemoveFromMruList(pExistingData);
if(Status == STATUS_SUCCESS)
{
Status = ResetSiteData(pExistingData);
if(Status != STATUS_SUCCESS)
{
if(InsertInMruList(pExistingData) == ERROR_SUCCESS)
{
InterlockedIncrement(&pExistingData->Header.RefCount);
}
}
}
}
}
else
{
RemoveAndDeleteSiteData(pExistingData);
}
pExistingData = (PDFSSITE_DATA) SHashNextEnumerate(&Iter, pSiteTable);
}
SHashFinishEnumerate(&Iter, pSiteTable);
return Status;
}
ULONG
DfsHashIpAddress(
void * pDfsAddress)
{
ULONG BucketNo = 0;
CHAR *pBuffer = (char *) &pDfsAddress;
CHAR *pBufferEnd = &pBuffer[4];
ULONG Ch = 0;
BucketNo = 0;
while (pBuffer != pBufferEnd) {
Ch = *pBuffer & 0xff;
BucketNo *= 131;
BucketNo += Ch;
pBuffer++;
}
return BucketNo;
}
int
CompareSiteIpAddress(void* pvKey1,
void* pvKey2)
{
int CompVal = 0;
ULONG_PTR IpAddress1 = (ULONG_PTR) pvKey1;
ULONG_PTR IpAddress2 = (ULONG_PTR) pvKey2;
if(IpAddress1 < IpAddress2)
{
CompVal = -1;
}
else if (IpAddress1 > IpAddress2)
{
CompVal = 1;
}
return CompVal;
}
VOID
DeallocateSiteCacheData(PVOID pPointer )
{
PDFSSITE_DATA pSiteStructure = (PDFSSITE_DATA)pPointer;
if(pPointer)
{
if (pSiteStructure->ClientSite != NULL)
{
pSiteStructure->ClientSite->ReleaseReference();
pSiteStructure->ClientSite = NULL;
}
delete [] (PBYTE)pPointer;
}
}