windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/cmp/asp/idgener.cpp
2020-09-26 16:20:57 +08:00

195 lines
4.6 KiB
C++

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1997 Microsoft Corporation. All Rights Reserved.
Component: ID Generator
File: Idgener.cpp
Owner: DmitryR
This is the ID Generator source file.
===================================================================*/
#include "denpre.h"
#pragma hdrstop
#include "Idgener.h"
#include "memchk.h"
/*===================================================================
CIdGenerator::CIdGenerator
NOTE: Constructor
Parameters:
Returns:
===================================================================*/
CIdGenerator::CIdGenerator()
: m_fInited(FALSE),
m_dwStartId(0),
m_dwLastId(0)
{
}
/*===================================================================
CIdGenerator::~CIdGenerator()
NOTE: Destructor
Parameters:
Returns:
===================================================================*/
CIdGenerator::~CIdGenerator()
{
if ( m_fInited )
DeleteCriticalSection( &m_csLock );
}
/*===================================================================
HRESULT CIdGenerator::Init()
NOTE: Seed new starting Id
Parameters:
Returns: HRESULT (could fail to create critical section)
===================================================================*/
HRESULT CIdGenerator::Init()
{
Assert(!m_fInited);
/*===
Seed the starting id
The starting Id should be:
1) random
2) not to close to recently generated starting ids
To accomplish the above, starting Id is in the
following (binary) format:
00TT.TTTT TTTT.TTTT TTT1.RRRR RRRR.RRRR
RRR is random number to introduce some
randomness
1 is needed to make sure the id is far
enough from 0
TTT is current time() in 4 second increments.
This means that 4 second in server restart
delay translates into 8,192 difference in
the starting Id (122880 sessions / minute).
17 bits of 4 sec intervals make a roll over
time of about 145 hours, hopefully longer
than a client's connection lifetime (not
that it REALLY matters).
00 in the highest bits is to make sure it
doesn't reach 0xffffffff too soon
===*/
DWORD dwRRR = rand() & 0x00000FFF;
DWORD dwTTT = (((DWORD)time(NULL)) >> 2) & 0x0001FFFF;
m_dwStartId = (dwTTT << 13) | (1 << 12) | dwRRR;
m_dwLastId = m_dwStartId;
HRESULT hr = S_OK;
ErrInitCriticalSection( &m_csLock, hr );
if ( FAILED( hr ) )
return hr;
m_fInited = TRUE;
return S_OK;
}
/*===================================================================
HRESULT CIdGenerator::Init(CIdGenerator StartId)
NOTE: Seed new starting Id with Id passed in
Parameters:
Returns: HRESULT (could fail to create critical section)
===================================================================*/
HRESULT CIdGenerator::Init(CIdGenerator & StartId)
{
Assert(!m_fInited);
m_dwStartId = StartId.m_dwStartId;
m_dwLastId = m_dwStartId;
HRESULT hr = NOERROR;
ErrInitCriticalSection( &m_csLock, hr );
if ( FAILED( hr ) )
return hr;
m_fInited = TRUE;
return NOERROR;
}
/*===================================================================
DWORD CIdGenerator::NewId()
NOTE: Generates new ID
Parameters:
Returns: generated ID
===================================================================*/
DWORD CIdGenerator::NewId()
{
Assert(m_fInited);
DWORD dwId;
EnterCriticalSection(&m_csLock);
dwId = ++m_dwLastId;
LeaveCriticalSection(&m_csLock);
if (dwId == INVALID_ID)
{
// doesn't happen very often do critical section again
// to make the above critical section shorter
EnterCriticalSection(&m_csLock);
// check again in case other thread changed it
if (m_dwLastId == INVALID_ID)
m_dwLastId = m_dwStartId; // roll over
m_dwLastId++;
LeaveCriticalSection(&m_csLock);
dwId = m_dwLastId;
}
return dwId;
}
/*===================================================================
BOOL CIdGenerator::IsValidId(DWORD dwId)
NOTE: Checks if the given Id is valid (with start-last range)
Parameters:
DWORD dwId Id value to check
Returns: generated ID
===================================================================*/
BOOL CIdGenerator::IsValidId
(
DWORD dwId
)
{
Assert(m_fInited);
return (dwId > m_dwStartId && dwId <= m_dwLastId);
}