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

698 lines
18 KiB
C++

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1996 Microsoft Corporation. All Rights Reserved.
Component: Session Manager
File: Sessmgr.h
Owner: PramodD
This is the session manager header file.
===================================================================*/
#ifndef SESSMGR_H
#define SESSMGR_H
#include "debug.h"
#include "idhash.h"
#include "idgener.h"
#include "compcol.h"
#include "request.h"
#include "response.h"
#include "server.h"
#include "viperint.h"
#include "ftm.h"
#include "memcls.h"
/*===================================================================
#defines
===================================================================*/
// Min/Max session timeout in minutes
#define SESSION_TIMEOUT_MIN 1 // 1 minute
#define SESSION_TIMEOUT_MAX 1440 // 1 day
// Master hash table sizes
#define SESSION_MASTERHASH_SIZE1_MAX 499
#define SESSION_MASTERHASH_SIZE2_MAX 31
#define SESSION_MASTERHASH_SIZE3_MAX 13
// Timeout bucket hash tables sizes
#define SESSION_TIMEOUTHASH_SIZE1_MAX 97
#define SESSION_TIMEOUTHASH_SIZE2_MAX 29
#define SESSION_TIMEOUTHASH_SIZE3_MAX 11
// Min/Max # of timeout buckets (hash tables)
#define SESSION_TIMEOUTBUCKETS_MIN 10
#define SESSION_TIMEOUTBUCKETS_MAX 45
// max value of GetTickCount()
#define DWT_MAX 0xFFFFFFFF
// session killer workitem default wait
#define MSEC_ONE_MINUTE 60000 // 1 min
#include "asptlb.h"
/*===================================================================
Forward declarations
===================================================================*/
class CAppln;
class CHitObj;
class CSession;
/*===================================================================
C S e s s i o n V a r i a n t s
===================================================================*/
class CSessionVariants : public IVariantDictionary
{
private:
ULONG m_cRefs; // ref count
CSession * m_pSession; // pointer to parent object
CompType m_ctColType; // collection type
CSupportErrorInfo m_ISupportErrImp; // implementation of ISupportErr
HRESULT ObjectNameFromVariant(VARIANT &vKey, WCHAR **ppwszName,
BOOL fVerify = FALSE);
public:
CSessionVariants();
~CSessionVariants();
HRESULT Init(CSession *pSession, CompType ctColType);
HRESULT UnInit();
// The Big Three
STDMETHODIMP QueryInterface(const GUID &, void **);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// OLE Automation Interface
STDMETHODIMP get_Item(VARIANT VarKey, VARIANT *pvar);
STDMETHODIMP put_Item(VARIANT VarKey, VARIANT var);
STDMETHODIMP putref_Item(VARIANT VarKey, VARIANT var);
STDMETHODIMP get_Key(VARIANT VarKey, VARIANT *pvar);
STDMETHODIMP get__NewEnum(IUnknown **ppEnumReturn);
STDMETHODIMP get_Count(int *pcValues);
STDMETHODIMP Remove(VARIANT VarKey);
STDMETHODIMP RemoveAll();
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS()
};
/*===================================================================
C S e s s i o n I D
===================================================================*/
struct CSessionId
{
DWORD m_dwId; // Session Id
DWORD m_dwR1; // Session Id random element 1
DWORD m_dwR2; // Session Id random element 2
CSessionId(DWORD dwId = INVALID_ID, DWORD dwR1 = 0, DWORD dwR2 = 0);
};
inline CSessionId::CSessionId(DWORD dwId, DWORD dwR1, DWORD dwR2)
{
m_dwId = dwId;
m_dwR1 = dwR1;
m_dwR2 = dwR2;
}
/*===================================================================
C S e s s i o n
===================================================================*/
class CSession : public ISessionObjectImpl, public CFTMImplementation
{
friend class CSessionMgr;
friend class CSessionVariants;
private:
//========= Misc flags
DWORD m_fInited : 1; // Are we initialized?
DWORD m_fLightWeight : 1; // Is in lightweight form?
DWORD m_fOnStartFailed : 1; // Session_OnStart failed?
DWORD m_fOnStartInvoked : 1; // Session_OnStart invoked?
DWORD m_fOnEndPresent : 1; // Need to invoke Session_OnEnd ?
DWORD m_fTimedOut : 1; // Session timed out?
DWORD m_fStateAcquired : 1; // Any property set (!m_fCanDelete)?
DWORD m_fCustomTimeout : 1; // Timeout different from standard?
DWORD m_fAbandoned : 1; // Session abandoned?
DWORD m_fTombstone : 1; // ASP is done with the session?
DWORD m_fInTOBucket : 1; // Session in a timeout bucket?
DWORD m_fSessCompCol : 1; // Component collection present?
DWORD m_fSecureSession : 1; // Is the session used over a secure line?
DWORD m_fCodePageSet : 1; // CodePage explicitly set?
DWORD m_fLCIDSet : 1; // LCID explicitly set?
//========= Pointers to related objects
CAppln *m_pAppln; // Session's Application
CHitObj *m_pHitObj; // Session's current HitObj
//========= Session's dictionaries for presenting component collection
CSessionVariants *m_pTaggedObjects;
CSessionVariants *m_pProperties;
//========= Session data
CSessionId m_Id; // Session ID + 2 random keys
DWORD m_dwExternId; // Session ID to be given out (Session.ID)
DWORD m_cRefs; // Ref count
DWORD m_cRequests; // Requests count
// Timeout when current time (in minutes) reaches this
// The timeout bucket is current_time mod #_of_buckets
DWORD m_dwmTimeoutTime;
long m_lCodePage; // Code page for this session
LCID m_lcid; // LCID for this session
long m_nTimeout; // Current time value in minutes
// to make session elem in the timeout bucket
CObjectListElem m_TOBucketElem;
#ifndef PERF_DISABLE
DWORD m_dwtInitTimestamp; // Timestamp of session creation for PERFMON
#endif
//========= Session's Component Collection
// to avoid the memory fragmentation component collection is
// aggregated here. its validity is indicated by m_fSessCompCol flag
CComponentCollection m_SessCompCol; // Session scope objects
//========= Viper Activity of this Session
CViperActivity m_Activity;
//========= Intrinsics for this Session
CRequest m_Request;
CResponse m_Response;
CServer m_Server;
//========= SupportErrorInfo
// Interface to indicate that we support ErrorInfo reporting
CSupportErrorInfo m_ISuppErrImp;
public:
CSession();
~CSession();
HRESULT Init(CAppln *pAppln, const CSessionId &Id);
// Convert to tombstone state
HRESULT UnInit();
// Convert to 'light-weight' state if possible
HRESULT MakeLightWeight();
// Create/Remove Session's component collection
HRESULT CreateComponentCollection();
HRESULT RemoveComponentCollection();
// Check if the session should be deleted
BOOL FShouldBeDeletedNow(BOOL fAtEndOfRequest);
// Non-delegating object IUnknown
STDMETHODIMP QueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// Tombstone stub
HRESULT CheckForTombstone();
// ISessionObject functions
STDMETHODIMP get_SessionID(BSTR *pbstrRet);
STDMETHODIMP get_Timeout(long *plVar);
STDMETHODIMP put_Timeout(long lVar);
STDMETHODIMP get_CodePage(long *plVar);
STDMETHODIMP put_CodePage(long lVar);
STDMETHODIMP get_Value(BSTR bstr, VARIANT FAR * pvar);
STDMETHODIMP put_Value(BSTR bstr, VARIANT var);
STDMETHODIMP putref_Value(BSTR bstr, VARIANT var);
STDMETHODIMP Abandon();
STDMETHODIMP get_LCID(long *plVar);
STDMETHODIMP put_LCID(long lVar);
STDMETHODIMP get_StaticObjects(IVariantDictionary **ppDictReturn);
STDMETHODIMP get_Contents(IVariantDictionary **ppDictReturn);
// inline methods to access member properties
CAppln *PAppln();
CHitObj *PHitObj();
CComponentCollection *PCompCol();
CViperActivity *PActivity();
CRequest *PRequest();
CResponse *PResponse();
CServer *PServer();
BOOL FCustomTimeout();
BOOL FAbandoned();
DWORD GetId();
BOOL FInTOBucket();
LCID GetLCID();
long GetCodePage();
DWORD GetTimeoutTime();
BOOL FSecureSession();
// inline methods to set member properties
void SetHitObj(CHitObj *pHitObj);
void SetOnStartFailedFlag();
void SetOnStartInvokedFlag();
void SetOnEndPresentFlag();
HRESULT SetLCID(LCID lcid);
// Misc inline methods
DWORD IncrementRequestsCount();
DWORD DecrementRequestsCount();
DWORD GetRequestsCount();
BOOL FCanDeleteWithoutExec();
BOOL FHasObjects();
BOOL FPassesIdSecurityCheck(DWORD dwR1, DWORD dwR2);
void AssignNewId(const CSessionId &Id);
void SetSecureSession(BOOL fSecure);
BOOL FCodePageSet();
BOOL FLCIDSet();
// AssertValid()
public:
#ifdef DBG
virtual void AssertValid() const;
#else
virtual void AssertValid() const {}
#endif
// Cache on per-class basis
ACACHE_INCLASS_DEFINITIONS()
// Trace Log info -- keep in both free & checked builds so that ntsd extension will work for both builds
// for FREE build, trace log is always NULL. Checked builds, it must be enabled.
static PTRACE_LOG gm_pTraceLog;
};
/*===================================================================
C S e s s i o n inlines
===================================================================*/
inline CAppln *CSession::PAppln()
{
Assert(m_fInited);
return m_pAppln;
}
inline CHitObj *CSession::PHitObj()
{
Assert(m_fInited);
return m_pHitObj;
}
inline CComponentCollection *CSession::PCompCol()
{
Assert(m_fInited);
return (m_fSessCompCol ? &m_SessCompCol : NULL);
}
inline CViperActivity *CSession::PActivity()
{
Assert(m_fInited);
return &m_Activity;
}
inline CRequest *CSession::PRequest()
{
Assert(m_fInited);
return &m_Request;
}
inline CResponse *CSession::PResponse()
{
Assert(m_fInited);
return &m_Response;
}
inline CServer *CSession::PServer()
{
Assert(m_fInited);
return &m_Server;
}
inline BOOL CSession::FCustomTimeout()
{
Assert(m_fInited);
return m_fCustomTimeout;
}
inline BOOL CSession::FAbandoned()
{
Assert(m_fInited);
return m_fAbandoned;
}
inline DWORD CSession::GetId()
{
Assert(m_fInited);
return m_Id.m_dwId;
}
inline BOOL CSession::FInTOBucket()
{
Assert(m_fInited);
return m_fInTOBucket;
}
inline LCID CSession::GetLCID()
{
Assert(m_fInited);
return (UINT)m_lcid;
}
inline long CSession::GetCodePage()
{
Assert(m_fInited);
return m_lCodePage == 0 ? GetACP() : m_lCodePage;
}
inline BOOL CSession::FCodePageSet()
{
Assert(m_fInited);
return (m_fCodePageSet);
}
inline BOOL CSession::FLCIDSet()
{
Assert(m_fInited);
return (m_fLCIDSet);
}
inline DWORD CSession::GetTimeoutTime()
{
Assert(m_fInited);
return m_dwmTimeoutTime;
}
inline BOOL CSession::FSecureSession()
{
Assert(m_fInited);
return m_fSecureSession;
}
inline void CSession::SetHitObj(CHitObj *pHitObj)
{
Assert(m_fInited);
Assert(pHitObj ? (m_pHitObj == NULL) : (m_pHitObj != NULL));
m_pHitObj = pHitObj;
}
inline void CSession::SetOnStartFailedFlag()
{
Assert(m_fInited);
m_fOnStartFailed = TRUE;
}
inline void CSession::SetOnStartInvokedFlag()
{
Assert(m_fInited);
m_fOnStartInvoked = TRUE;
}
inline void CSession::SetOnEndPresentFlag()
{
Assert(m_fInited);
m_fOnEndPresent = TRUE;
}
inline HRESULT CSession::SetLCID(LCID lcid)
{
Assert(m_fInited);
if ((LOCALE_SYSTEM_DEFAULT == lcid) || IsValidLocale(lcid, LCID_INSTALLED))
{
m_lcid = lcid;
return S_OK;
}
else
{
return E_FAIL;
}
}
inline DWORD CSession::IncrementRequestsCount()
{
Assert(m_fInited);
return InterlockedIncrement((LPLONG)&m_cRequests);
}
inline DWORD CSession::DecrementRequestsCount()
{
Assert(m_fInited);
return InterlockedDecrement((LPLONG)&m_cRequests);
}
inline DWORD CSession::GetRequestsCount()
{
Assert(m_fInited);
return m_cRequests;
}
inline BOOL CSession::FCanDeleteWithoutExec()
{
// Return TRUE to delete CSession right away or FALSE to
// post Viper request to execute Session_OnEnd()
return (m_fOnStartFailed || !m_fOnEndPresent);
}
inline BOOL CSession::FHasObjects()
{
return m_fSessCompCol && m_SessCompCol.FHasObjects();
}
inline BOOL CSession::FPassesIdSecurityCheck(DWORD dwR1, DWORD dwR2)
{
Assert(m_fInited);
return (m_Id.m_dwR1 == dwR1 && m_Id.m_dwR2 == dwR2);
}
inline void CSession::AssignNewId(const CSessionId &Id)
{
Assert(m_fInited);
m_Id = Id;
}
inline void CSession::SetSecureSession(BOOL fSecure)
{
Assert(m_fInited);
m_fSecureSession = fSecure;
}
/*===================================================================
C S e s s i o n M g r
===================================================================*/
class CSessionMgr
{
private:
// Flags
DWORD m_fInited : 1; // Are we initialized?
// Application
CAppln *m_pAppln;
// Sessions master hash table
CIdHashTableWithLock m_htidMaster;
// Number of posted Session Cleanup requests
DWORD m_cSessionCleanupRequests;
// Timeout buckets
DWORD m_cTimeoutBuckets;
CObjectListWithLock *m_rgolTOBuckets;
// Session killer scheduler workitem
DWORD m_idSessionKiller; // workitem id
DWORD m_dwmCurrentTime; // current time in minutes since start
DWORD m_dwtNextSessionKillerTime; // next session killer time
public:
CSessionMgr();
~CSessionMgr();
// Init/Unit
HRESULT Init(CAppln *pAppln);
HRESULT UnInit();
// Add/remove session killer workitem
HRESULT ScheduleSessionKiller();
HRESULT UnScheduleSessionKiller();
BOOL FIsSessionKillerScheduled();
// Lock/Unlock master hash table
HRESULT LockMaster();
HRESULT UnLockMaster();
// Lock/Unlock a timeout bucket hash table
HRESULT LockTOBucket(DWORD iBucket);
HRESULT UnLockTOBucket(DWORD iBucket);
// Get current time in minute ticks
DWORD GetCurrentTime();
// Set the time when the session should be gone
HRESULT UpdateSessionTimeoutTime(CSession *pSession);
// Calculate which timeout bucket the session's in
DWORD GetSessionTOBucket(CSession *pSession);
// Generate new ID and cookie
HRESULT GenerateIdAndCookie(CSessionId *pId, char *pszCookie);
// Create new session object
HRESULT NewSession(const CSessionId &Id, CSession **ppSession);
// Reassign session's Id (reinsert session into master hash)
HRESULT ChangeSessionId(CSession *pSession, const CSessionId &Id);
// Master hash table manipulations
HRESULT AddToMasterHash(CSession *pSession);
HRESULT RemoveFromMasterHash(CSession *pSession);
HRESULT FindInMasterHash(const CSessionId &Id, CSession **ppSession);
// Insert/remove session into the timeout bucket hash table
HRESULT AddSessionToTOBucket(CSession *pSession);
HRESULT RemoveSessionFromTOBucket(CSession *pSession, BOOL fLock = TRUE);
// Delete session now or queue for deletion
HRESULT DeleteSession(CSession *pSession, BOOL fInSessActivity = FALSE);
// Delete expired sessions from a given bucket
HRESULT DeleteExpiredSessions(DWORD iBucket);
// Delete all sessions (application shut-down code)
HRESULT DeleteAllSessions(BOOL fForce);
// Static iterator call back to delete all sessions
static IteratorCallbackCode DeleteAllSessionsCB(void *, void *, void *);
// The Session Killer
static VOID WINAPI SessionKillerSchedulerCallback(VOID *pv);
// Incr/Decr/Get number of posted Session Cleanup requests
void IncrementSessionCleanupRequestCount();
void DecrementSessionCleanupRequestCount();
DWORD GetNumSessionCleanupRequests();
// AssertValid()
public:
#ifdef DBG
virtual void AssertValid() const;
#else
virtual void AssertValid() const {}
#endif
};
inline BOOL CSessionMgr::FIsSessionKillerScheduled()
{
return (m_idSessionKiller != 0);
}
inline HRESULT CSessionMgr::LockMaster()
{
m_htidMaster.Lock();
return S_OK;
}
inline HRESULT CSessionMgr::UnLockMaster()
{
m_htidMaster.UnLock();
return S_OK;
}
inline HRESULT CSessionMgr::LockTOBucket(DWORD iBucket)
{
Assert(m_rgolTOBuckets);
Assert(iBucket < m_cTimeoutBuckets);
m_rgolTOBuckets[iBucket].Lock();
return S_OK;
}
inline HRESULT CSessionMgr::UnLockTOBucket(DWORD iBucket)
{
Assert(m_rgolTOBuckets);
Assert(iBucket < m_cTimeoutBuckets);
m_rgolTOBuckets[iBucket].UnLock();
return S_OK;
}
inline DWORD CSessionMgr::GetCurrentTime()
{
return m_dwmCurrentTime;
}
inline HRESULT CSessionMgr::UpdateSessionTimeoutTime(CSession *pSession)
{
Assert(pSession);
// remember when the session times out
pSession->m_dwmTimeoutTime =
m_dwmCurrentTime + pSession->m_nTimeout + 1;
return S_OK;
}
inline DWORD CSessionMgr::GetSessionTOBucket(CSession *pSession)
{
Assert(pSession->m_fInited);
return (pSession->m_dwmTimeoutTime % m_cTimeoutBuckets);
}
inline HRESULT CSessionMgr::AddToMasterHash(CSession *pSession)
{
Assert(m_fInited);
return m_htidMaster.AddObject(pSession->GetId(), pSession);
}
inline HRESULT CSessionMgr::RemoveFromMasterHash(CSession *pSession)
{
Assert(m_fInited);
return m_htidMaster.RemoveObject(pSession->GetId());
}
inline void CSessionMgr::IncrementSessionCleanupRequestCount()
{
InterlockedIncrement((LPLONG)&m_cSessionCleanupRequests);
}
inline void CSessionMgr::DecrementSessionCleanupRequestCount()
{
InterlockedDecrement((LPLONG)&m_cSessionCleanupRequests);
}
inline DWORD CSessionMgr::GetNumSessionCleanupRequests()
{
return m_cSessionCleanupRequests;
}
/*===================================================================
G l o b a l s
===================================================================*/
// There are multiple session managers (one per application)
// The following variables are 1 per ASP.DLL
extern unsigned long g_nSessions;
extern CIdGenerator g_SessionIdGenerator;
extern CIdGenerator g_ExposedSessionIdGenerator;
#endif // SESSMGR_H