/*=================================================================== 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