windows-nt/Source/XPSP1/NT/net/rras/ip/nath323/crv.cpp
2020-09-26 16:20:57 +08:00

267 lines
7.5 KiB
C++

#include "stdafx.h"
#include "time.h"
#include "crv.h"
inline BOOL
IsBitOn(
IN BYTE *Byte,
IN BYTE BitNumber
)
{
// the bit number must be in the range [0..8)
_ASSERTE(BitNumber < 8);
return (*Byte & (1 << BitNumber));
}
inline void
SetBit(
IN BYTE *Byte,
IN BYTE BitNumber,
IN BOOL OnOff
)
{
// the bit number must be in the range [0..8)
_ASSERTE(BitNumber < 8);
if(OnOff)
{
// Turn the bit on
*Byte |= (1 << BitNumber);
}
else
{ // Turn the bit off
*Byte &= ~(1 << BitNumber);
}
}
///////////////////////////////////////////////////////////////////////////////
// //
// CRV allocator variables and functions. //
// //
///////////////////////////////////////////////////////////////////////////////
// these const values are needed for CRV generation
// max number of random number generations needed to
// get a low probability of failure. An assumption of max 10^3
// active calls at a time in a space of 2^15 crv values implies
// that we can reach 1 in 10^6 failure prob. in 4 generations
const BYTE MAX_CALL_REF_RAND_GEN = 4;
// number of different CRV values
const WORD TOTAL_CRVS = 0x8000; // 2^15;
// number of bits needed for the crv bit map
const WORD CRV_BIT_MAP_SIZE = (TOTAL_CRVS/8); // (2^15)/8;
// CODEWORK: We are allocating a huge array 0x1000 bytes - is this okay ?
// number of allocated crvs.
// currently this is only used for a sanity check. it may be used for
// determining the max number of random numbers to generate before trying
// a linear search through the bitmap.
WORD g_NumAllocatedCRVs;
// bitmap array in which each bit represents whether or not the corresponding
// crv has been allocated. The mapping between crv value N and a bit is -
// N <-> CRVBitMap[N/8] byte, N%8 bit
// NOTE: This must be zero'ed out during initialization as a bit is on iff
// it has been allocated
BYTE g_CRVBitMap[CRV_BIT_MAP_SIZE];
// critical section to synchronize access to the bit map data structures
CRITICAL_SECTION g_CRVBitMapCritSec;
HRESULT InitCrvAllocator()
{
// no crvs have been allocated
g_NumAllocatedCRVs = 0;
// zero out the bit map
ZeroMemory(g_CRVBitMap, CRV_BIT_MAP_SIZE);
// 0 is not a valid call ref value and it cannot be allocated or
// deallocated we set the first bit of the first byte to 1 so that
// it is never returned by AllocCallRefVal
g_CRVBitMap[0] = 0x80;
InitializeCriticalSection(&g_CRVBitMapCritSec);
// Seed the random-number generator with current time so that
// the numbers will be different every time we run.
srand( (unsigned)time( NULL ) );
return S_OK;
}
HRESULT CleanupCrvAllocator()
{
DeleteCriticalSection(&g_CRVBitMapCritSec);
return S_OK;
}
// The CRV allocator is locked when this function is called.
// fallback algorithm to linearly search through the bitmap
// for a free call ref value. this should be called very rarely
BOOL
LinearBitMapSearch(
OUT CALL_REF_TYPE &CallRefVal
)
{
// check each byte in the bit map array
// NOTE: we can check 8 bytes at a time using int64, but since this method is
// only called extremely rarely, there is no need to complicate the logic
for(WORD i=0; i < CRV_BIT_MAP_SIZE; i++)
{
// check the byte to see if there is any use checking its bits
if (0xFF == g_CRVBitMap[i])
{
continue;
}
// check all bits from bit 0 to bit 7
for (BYTE j=0; j < 8; j++)
{
if (!IsBitOn(&g_CRVBitMap[i], j))
{
// set the bit on
SetBit(&g_CRVBitMap[i], j, TRUE);
// byte*8 + the bit number gives us the call ref value
CallRefVal = (i << 3) + j;
// increment the number of allocated crvs
g_NumAllocatedCRVs++;
return TRUE;
}
}
}
return FALSE;
}
// CODEWORK: Is all this stuff really worth it ?
// rand() is typically expensive. We probably can leave it this way for now.
//
// try to find a free call ref value by randomly generating one and
// then checking if its free. The assumption here is that the max
// number of call ref values is much less than the size of the call ref
// universe. we check this for a max of MAX_CALL_REF_RAND_GEN attempts.
// MAX_CALL_REF_RAND_GEN can be derived so that the probability
// of failure is very low (say 1 in a million). This may be derived from
// the number of call ref values currently available and the size of
// the call ref value universe. For ex. we believe that atmost 1000 calls
// may be active at any time and the crv universe is of size 2^15. This
// means that the prob. of failure for EACH attempt is < 1/32. Hence 4
// attempts would give us a 1 in a million probability of failure
BOOL
AllocCallRefVal(
OUT CALL_REF_TYPE &CallRefVal
)
{
///////////////////////////////
//// LOCK the CRV ALLOCATOR
///////////////////////////////
EnterCriticalSection(&g_CRVBitMapCritSec);
//AUTO_CRIT_LOCK AutoCritLock(g_CRVBitMapCritSec.GetCritSec());
// sanity check to see if we have used up all crvs
if (TOTAL_CRVS == g_NumAllocatedCRVs)
{
DebugF( _T("AllocCallRefVal(&CallRefVal) returning FALSE, all CRVs used up\n"));
LeaveCriticalSection(&g_CRVBitMapCritSec);
return FALSE;
}
// check if crv is free, for a max of MAX_CALL_REF_RAND_GEN times
for (BYTE i=0; i < MAX_CALL_REF_RAND_GEN; i++)
{
// generate random number
// NOTE: the range is [0..RAND_MAX] and RAND_MAX is defined as 0x7fff
// since this is also the range of legal CRVs, we don't need to convert
// the generated number to a new range
CALL_REF_TYPE NewCRV = (CALL_REF_TYPE) rand();
// identify the byte number corresponding to the crv.
// we don't check just try the corresponding bit and check other
// bits in the byte as well. this is done to increase the chances of
// finding a free bit for each random generation
WORD ByteNum = NewCRV / 8;
// check all bits from bit 0 to bit 7
for (BYTE j=0; j < 8; j++)
{
if (!IsBitOn(&g_CRVBitMap[ByteNum], j))
{
// set the bit on
SetBit(&g_CRVBitMap[ByteNum], j, TRUE);
// byte*8 + the bit number gives us the call ref value
CallRefVal = (ByteNum << 3) + j;
// increment the number of allocated crvs
g_NumAllocatedCRVs++;
LeaveCriticalSection(&g_CRVBitMapCritSec);
return TRUE;
}
}
}
// we reach here in extremely rare cases. we can now try a linear search
// through the crv bitmap for a free crv
DebugF(_T("AllocCallRefVal() trying linear search.\n"));
BOOL fRetVal = LinearBitMapSearch(CallRefVal);
LeaveCriticalSection(&g_CRVBitMapCritSec);
return fRetVal;
}
// frees a currently allocated call ref value
void
DeallocCallRefVal(
IN CALL_REF_TYPE CallRefVal
)
{
// 0 is not a valid call ref value and it cannot be allocated or
// deallocated we set the first bit of the first byte to 1 so that
// it is never returned by AllocCallRefVal
if (0 == CallRefVal)
{
_ASSERTE(FALSE);
return;
}
// determine the byte and the bit
WORD ByteNum = CallRefVal / 8;
BYTE BitNum = CallRefVal % 8;
// acquire critical section
EnterCriticalSection(&g_CRVBitMapCritSec);
// the bit should be on (to indicate that its in use)
if (IsBitOn(&g_CRVBitMap[ByteNum], BitNum))
{
// set the bit off
SetBit(&g_CRVBitMap[ByteNum], BitNum, FALSE);
// decrement number of available crvs
g_NumAllocatedCRVs--;
}
else {
DebugF(_T("DeallocCallRefVal: warning, bit was not allocated to begin with, crv %04XH\n"),
CallRefVal);
}
LeaveCriticalSection(&g_CRVBitMapCritSec);
}