Source code of Windows XP (NT5)
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.

2464 lines
55 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Session Object Manager
  6. File: Sessmgr.cpp
  7. Owner: PramodD
  8. This is the Session Manager source file.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "idgener.h"
  13. #include "perfdata.h"
  14. #include "randgen.h"
  15. // ATQ Scheduler
  16. #include "issched.hxx"
  17. #include "MemChk.h"
  18. #pragma warning (disable: 4355) // ignore: "'this' used in base member init
  19. /*===================================================================
  20. G l o b a l s
  21. ===================================================================*/
  22. PTRACE_LOG CSession::gm_pTraceLog = NULL;
  23. unsigned long g_nSessions = 0;
  24. CIdGenerator g_SessionIdGenerator;
  25. CIdGenerator g_ExposedSessionIdGenerator;
  26. LONG g_nSessionObjectsActive = 0;
  27. // On app restart post session cleanup requests so many at a time
  28. #define SUGGESTED_SESSION_CLEANUP_REQUESTS_MAX 500
  29. /*===================================================================
  30. C S e s s i o n V a r i a n t s
  31. ===================================================================*/
  32. /*===================================================================
  33. CSessionVariants::CSessionVariants
  34. Constructor
  35. Parameters:
  36. Returns:
  37. ===================================================================*/
  38. CSessionVariants::CSessionVariants()
  39. :
  40. m_cRefs(1),
  41. m_pSession(NULL),
  42. m_ctColType(ctUnknown),
  43. m_ISupportErrImp(this, this, IID_IVariantDictionary)
  44. {
  45. CDispatch::Init(IID_IVariantDictionary);
  46. }
  47. /*===================================================================
  48. CSessionVariants::~CSessionVariants
  49. Destructor
  50. Parameters:
  51. Returns:
  52. ===================================================================*/
  53. CSessionVariants::~CSessionVariants()
  54. {
  55. Assert(!m_pSession);
  56. }
  57. /*===================================================================
  58. CSessionVariants::Init
  59. Initialize object
  60. Parameters:
  61. pSession Session
  62. ctColType Type of variables to expose in the collection
  63. e.g. Tagged objects or Properties
  64. Returns:
  65. HRESULT
  66. ===================================================================*/
  67. HRESULT CSessionVariants::Init
  68. (
  69. CSession *pSession,
  70. CompType ctColType
  71. )
  72. {
  73. Assert(pSession);
  74. pSession->AddRef();
  75. Assert(!m_pSession);
  76. m_pSession = pSession;
  77. m_ctColType = ctColType;
  78. return S_OK;
  79. }
  80. /*===================================================================
  81. CSessionVariants::UnInit
  82. UnInitialize object
  83. Parameters:
  84. Returns:
  85. HRESULT
  86. ===================================================================*/
  87. HRESULT CSessionVariants::UnInit()
  88. {
  89. if (m_pSession)
  90. {
  91. m_pSession->Release();
  92. m_pSession = NULL;
  93. }
  94. return S_OK;
  95. }
  96. /*===================================================================
  97. CSessionVariants::QueryInterface
  98. CSessionVariants::AddRef
  99. CSessionVariants::Release
  100. IUnknown members for CSessionVariables object.
  101. ===================================================================*/
  102. STDMETHODIMP CSessionVariants::QueryInterface
  103. (
  104. REFIID iid,
  105. void **ppvObj
  106. )
  107. {
  108. if (iid == IID_IUnknown || iid == IID_IDispatch ||
  109. iid == IID_IVariantDictionary)
  110. {
  111. AddRef();
  112. *ppvObj = this;
  113. return S_OK;
  114. }
  115. else if (iid == IID_ISupportErrorInfo)
  116. {
  117. m_ISupportErrImp.AddRef();
  118. *ppvObj = &m_ISupportErrImp;
  119. return S_OK;
  120. }
  121. *ppvObj = NULL;
  122. return E_NOINTERFACE;
  123. }
  124. STDMETHODIMP_(ULONG) CSessionVariants::AddRef()
  125. {
  126. return InterlockedIncrement((LPLONG)&m_cRefs);
  127. }
  128. STDMETHODIMP_(ULONG) CSessionVariants::Release()
  129. {
  130. if (InterlockedDecrement((LPLONG)&m_cRefs) > 0)
  131. return m_cRefs;
  132. delete this;
  133. return 0;
  134. }
  135. /*===================================================================
  136. CSessionVariants::ObjectNameFromVariant
  137. Gets name from variant. Resolves operations by index.
  138. Allocates memory for name.
  139. Parameters:
  140. vKey VARIANT
  141. ppwszName [out] allocated name
  142. fVerify flag - check existance if named
  143. Returns:
  144. HRESULT
  145. ===================================================================*/
  146. HRESULT CSessionVariants::ObjectNameFromVariant
  147. (
  148. VARIANT &vKey,
  149. WCHAR **ppwszName,
  150. BOOL fVerify
  151. )
  152. {
  153. *ppwszName = NULL;
  154. VARIANT *pvarKey = &vKey;
  155. VARIANT varKeyCopy;
  156. VariantInit(&varKeyCopy);
  157. if (V_VT(pvarKey) != VT_BSTR && V_VT(pvarKey) != VT_I2 && V_VT(pvarKey) != VT_I4)
  158. {
  159. if (FAILED(VariantResolveDispatch(&varKeyCopy, &vKey, IID_IVariantDictionary, IDE_SESSION)))
  160. {
  161. ExceptionId(IID_IVariantDictionary, IDE_SESSION, IDE_EXPECTING_STR);
  162. VariantClear(&varKeyCopy);
  163. return E_FAIL;
  164. }
  165. pvarKey = &varKeyCopy;
  166. }
  167. LPWSTR pwszName = NULL;
  168. switch (V_VT(pvarKey))
  169. {
  170. case VT_BSTR:
  171. {
  172. pwszName = V_BSTR(pvarKey);
  173. if (fVerify && pwszName)
  174. {
  175. CComponentObject *pObj = NULL;
  176. Assert(m_pSession);
  177. Assert(m_pSession->PCompCol());
  178. if (m_ctColType == ctTagged)
  179. m_pSession->PCompCol()->GetTagged(pwszName, &pObj);
  180. else
  181. m_pSession->PCompCol()->GetProperty(pwszName, &pObj);
  182. if (!pObj || pObj->GetType() != m_ctColType)
  183. pwszName = NULL; // as if not found
  184. }
  185. break;
  186. }
  187. case VT_I1: case VT_I2: case VT_I8:
  188. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  189. case VT_R4: case VT_R8:
  190. // Coerce all integral types to VT_I4
  191. if (FAILED(VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  192. return E_FAIL;
  193. // fallthru to VT_I4
  194. case VT_I4:
  195. {
  196. int i;
  197. HRESULT hr;
  198. // Look up the object by index
  199. i = V_I4(pvarKey);
  200. if (i > 0)
  201. {
  202. Assert(m_pSession);
  203. Assert(m_pSession->PCompCol());
  204. hr = m_pSession->PCompCol()->GetNameByIndex
  205. (
  206. m_ctColType,
  207. i,
  208. &pwszName
  209. );
  210. if (FAILED(hr))
  211. return DISP_E_BADINDEX;
  212. }
  213. else
  214. {
  215. ExceptionId(IID_IVariantDictionary, IDE_SESSION, IDE_BAD_ARRAY_INDEX);
  216. return E_FAIL;
  217. }
  218. break;
  219. }
  220. }
  221. VariantClear(&varKeyCopy);
  222. if (!pwszName)
  223. return S_OK;
  224. // Copy name
  225. *ppwszName = StringDupW(pwszName);
  226. return S_OK;
  227. }
  228. /*===================================================================
  229. CSessionVariants::get_Item
  230. Function called from DispInvoke to get values from the
  231. SessionVariables collection.
  232. Parameters:
  233. vKey VARIANT [in], which parameter to get the value of
  234. - integers access collection as an array
  235. pvarReturn VARIANT *, [out] value of the requested parameter
  236. Returns:
  237. S_OK on success, E_FAIL on failure.
  238. ===================================================================*/
  239. HRESULT CSessionVariants::get_Item
  240. (
  241. VARIANT varKey,
  242. VARIANT *pVar
  243. )
  244. {
  245. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  246. return E_FAIL;
  247. // Initialize return value
  248. VariantInit(pVar);
  249. if (!m_pSession->PHitObj() || !m_pSession->PCompCol())
  250. return S_OK; // return empty variant
  251. CHitObj *pHitObj = m_pSession->PHitObj();
  252. // Get name
  253. WCHAR *pwszName = NULL;
  254. HRESULT hr = ObjectNameFromVariant(varKey, &pwszName);
  255. if (!pwszName)
  256. return S_OK; // bogus index - no error
  257. // Find object by name
  258. CComponentObject *pObj = NULL;
  259. if (m_ctColType == ctTagged)
  260. {
  261. pHitObj->GetComponent(csSession, pwszName, CbWStr(pwszName), &pObj);
  262. if (pObj && (pObj->GetType() != ctTagged))
  263. pObj = NULL;
  264. }
  265. else
  266. {
  267. pHitObj->GetPropertyComponent(csSession, pwszName, &pObj);
  268. }
  269. free(pwszName);
  270. if (!pObj)
  271. return S_OK;
  272. // return the variant
  273. return pObj->GetVariant(pVar);
  274. }
  275. /*===================================================================
  276. CSessionVariants::put_Item
  277. IVariantsDictionary implementation.
  278. Implement property put by dereferencing variants before
  279. calling putref.
  280. Parameters:
  281. VARIANT varKey Name of the variable to set
  282. VARIANT Var Value/object to set for the variable
  283. Returns:
  284. HRESULT S_OK on success
  285. ===================================================================*/
  286. STDMETHODIMP CSessionVariants::put_Item
  287. (
  288. VARIANT varKey,
  289. VARIANT Var
  290. )
  291. {
  292. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  293. return E_FAIL;
  294. if (m_ctColType == ctTagged)
  295. {
  296. ExceptionId(IID_IVariantDictionary, IDE_SESSION,
  297. IDE_CANT_MOD_STATICOBJECTS);
  298. return E_FAIL;
  299. }
  300. if (!m_pSession->PHitObj())
  301. return E_FAIL;
  302. Assert(m_ctColType == ctProperty);
  303. // Resolve the variant
  304. VARIANT varResolved;
  305. HRESULT hr = VariantResolveDispatch
  306. (
  307. &varResolved,
  308. &Var,
  309. IID_ISessionObject,
  310. IDE_SESSION
  311. );
  312. if (FAILED(hr))
  313. return hr; // exception already raised
  314. // Get name
  315. WCHAR *pwszName = NULL;
  316. hr = ObjectNameFromVariant(varKey, &pwszName);
  317. if (!pwszName)
  318. return hr;
  319. hr = m_pSession->PHitObj()->SetPropertyComponent
  320. (
  321. csSession,
  322. pwszName,
  323. &varResolved
  324. );
  325. free(pwszName);
  326. VariantClear(&varResolved);
  327. return hr;
  328. }
  329. /*===================================================================
  330. CSessionVariants::putref_Item
  331. IVariantsDictionary implementation.
  332. Implement property put be reference.
  333. Parameters:
  334. VARIANT varKey Name of the variable to set
  335. VARIANT Var Value/object to set for the variable
  336. Returns:
  337. HRESULT S_OK on success
  338. ===================================================================*/
  339. STDMETHODIMP CSessionVariants::putref_Item
  340. (
  341. VARIANT varKey,
  342. VARIANT Var
  343. )
  344. {
  345. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  346. return E_FAIL;
  347. if (m_ctColType == ctTagged)
  348. {
  349. ExceptionId(IID_IVariantDictionary, IDE_SESSION,
  350. IDE_CANT_MOD_STATICOBJECTS);
  351. return E_FAIL;
  352. }
  353. if (FIsIntrinsic(&Var))
  354. {
  355. ExceptionId(IID_IVariantDictionary, IDE_SESSION,
  356. IDE_SESSION_CANT_STORE_INTRINSIC);
  357. return E_FAIL;
  358. }
  359. if (!m_pSession->PHitObj())
  360. return E_FAIL;
  361. Assert(m_ctColType == ctProperty);
  362. // Get name
  363. WCHAR *pwszName = NULL;
  364. HRESULT hr = ObjectNameFromVariant(varKey, &pwszName);
  365. if (!pwszName)
  366. return hr;
  367. hr = m_pSession->PHitObj()->SetPropertyComponent
  368. (
  369. csSession,
  370. pwszName,
  371. &Var
  372. );
  373. free(pwszName);
  374. return hr;
  375. }
  376. /*===================================================================
  377. CSessionVariants::get_Key
  378. Function called from DispInvoke to get Keys from the SessionVariables collection.
  379. Parameters:
  380. vKey VARIANT [in], which parameter to get the value of - integers access collection as an array
  381. pvarReturn VARIANT *, [out] value of the requested parameter
  382. Returns:
  383. S_OK on success, E_FAIL on failure.
  384. ===================================================================*/
  385. HRESULT CSessionVariants::get_Key
  386. (
  387. VARIANT varKey,
  388. VARIANT *pVar
  389. )
  390. {
  391. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  392. return E_FAIL;
  393. VariantInit(pVar);
  394. if (!m_pSession->PHitObj() || !m_pSession->PCompCol())
  395. return S_OK;
  396. // Get name
  397. WCHAR *pwszName = NULL;
  398. HRESULT hr = ObjectNameFromVariant(varKey, &pwszName, TRUE);
  399. if (!pwszName)
  400. return S_OK; // no error if bogus index
  401. // Return BSTr
  402. BSTR bstrT = SysAllocString(pwszName);
  403. free(pwszName);
  404. if (!bstrT)
  405. return E_OUTOFMEMORY;
  406. V_VT(pVar) = VT_BSTR;
  407. V_BSTR(pVar) = bstrT;
  408. return S_OK;
  409. }
  410. /*===================================================================
  411. CSessionVariants::get_Count
  412. Parameters:
  413. pcValues - count is stored in *pcValues
  414. ===================================================================*/
  415. STDMETHODIMP CSessionVariants::get_Count
  416. (
  417. int *pcValues
  418. )
  419. {
  420. *pcValues = 0;
  421. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  422. return E_FAIL;
  423. if (m_pSession->PCompCol())
  424. {
  425. if (m_ctColType == ctTagged)
  426. *pcValues = m_pSession->PCompCol()->GetTaggedObjectCount();
  427. else
  428. *pcValues = m_pSession->PCompCol()->GetPropertyCount();
  429. }
  430. return S_OK;
  431. }
  432. /*===================================================================
  433. CSessionVariants::get__NewEnum
  434. Return a new enumerator
  435. ===================================================================*/
  436. HRESULT CSessionVariants::get__NewEnum
  437. (
  438. IUnknown **ppEnumReturn
  439. )
  440. {
  441. *ppEnumReturn = NULL;
  442. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  443. return E_FAIL;
  444. CVariantsIterator *pIterator = new CVariantsIterator
  445. (
  446. m_pSession,
  447. m_ctColType
  448. );
  449. if (pIterator == NULL)
  450. {
  451. ExceptionId(IID_IVariantDictionary, IDE_SESSION, IDE_OOM);
  452. return E_OUTOFMEMORY;
  453. }
  454. *ppEnumReturn = pIterator;
  455. return S_OK;
  456. }
  457. /*===================================================================
  458. CSessionVariants::Remove
  459. Remove item from the collection
  460. Parameters:
  461. varKey VARIANT [in]
  462. Returns:
  463. S_OK on success, E_FAIL on failure.
  464. ===================================================================*/
  465. STDMETHODIMP CSessionVariants::Remove
  466. (
  467. VARIANT varKey
  468. )
  469. {
  470. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  471. return E_FAIL;
  472. if (m_ctColType == ctTagged)
  473. {
  474. ExceptionId(IID_IVariantDictionary, IDE_SESSION,
  475. IDE_CANT_MOD_STATICOBJECTS);
  476. return E_FAIL;
  477. }
  478. Assert(m_ctColType == ctProperty);
  479. // Get name
  480. WCHAR *pwszName = NULL;
  481. ObjectNameFromVariant(varKey, &pwszName);
  482. if (!pwszName)
  483. return S_OK;
  484. CComponentCollection *pCompCol = m_pSession->PCompCol();
  485. if (pCompCol)
  486. pCompCol->RemoveProperty(pwszName);
  487. free(pwszName);
  488. return S_OK;
  489. }
  490. /*===================================================================
  491. CSessionVariants::RemoveAll
  492. Remove all items from the collection
  493. Parameters:
  494. Returns:
  495. S_OK on success, E_FAIL on failure.
  496. ===================================================================*/
  497. STDMETHODIMP CSessionVariants::RemoveAll()
  498. {
  499. if (!m_pSession || FAILED(m_pSession->CheckForTombstone()))
  500. return E_FAIL;
  501. if (m_ctColType == ctTagged)
  502. {
  503. ExceptionId(IID_IVariantDictionary, IDE_SESSION,
  504. IDE_CANT_MOD_STATICOBJECTS);
  505. return E_FAIL;
  506. }
  507. Assert(m_ctColType == ctProperty);
  508. CComponentCollection *pCompCol = m_pSession->PCompCol();
  509. if (pCompCol)
  510. {
  511. pCompCol->RemoveAllProperties();
  512. }
  513. return S_OK;
  514. }
  515. /*===================================================================
  516. C S e s s i o n
  517. ===================================================================*/
  518. /*===================================================================
  519. CSession::CSession
  520. Constructor
  521. Parameters:
  522. Returns:
  523. ===================================================================*/
  524. CSession::CSession()
  525. :
  526. m_fInited(FALSE),
  527. m_fLightWeight(FALSE),
  528. m_fOnStartFailed(FALSE),
  529. m_fOnStartInvoked(FALSE),
  530. m_fOnEndPresent(FALSE),
  531. m_fTimedOut(FALSE),
  532. m_fStateAcquired(FALSE),
  533. m_fCustomTimeout(FALSE),
  534. m_fAbandoned(FALSE),
  535. m_fTombstone(FALSE),
  536. m_fInTOBucket(FALSE),
  537. m_fSessCompCol(FALSE),
  538. m_fCodePageSet(FALSE),
  539. m_fLCIDSet(FALSE),
  540. m_Request(static_cast<ISessionObject *>(this)),
  541. m_Response(static_cast<ISessionObject *>(this)),
  542. m_Server(static_cast<ISessionObject *>(this)),
  543. m_pAppln(NULL),
  544. m_pHitObj(NULL),
  545. m_pTaggedObjects(NULL),
  546. m_pProperties(NULL),
  547. m_Id(INVALID_ID, 0, 0),
  548. m_dwExternId(INVALID_ID),
  549. m_cRefs(1),
  550. m_cRequests(0),
  551. m_dwmTimeoutTime(0),
  552. m_nTimeout(0),
  553. #ifndef PERF_DISABLE
  554. m_dwtInitTimestamp(0),
  555. #endif
  556. m_lCodePage(0),
  557. m_lcid(LOCALE_SYSTEM_DEFAULT),
  558. m_fSecureSession(FALSE)
  559. {
  560. m_lCodePage = GetACP();
  561. m_ISuppErrImp.Init(static_cast<ISessionObject *>(this),
  562. static_cast<ISessionObject *>(this),
  563. IID_ISessionObject);
  564. CDispatch::Init(IID_ISessionObject);
  565. InterlockedIncrement(&g_nSessionObjectsActive);
  566. IF_DEBUG(SESSION)
  567. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  568. }
  569. /*===================================================================
  570. CSession::~CSession
  571. Destructor
  572. Parameters:
  573. Returns:
  574. ===================================================================*/
  575. CSession::~CSession()
  576. {
  577. Assert(m_fTombstone); // must be tombstoned before destructor
  578. Assert(m_cRefs == 0); // must have 0 ref count
  579. InterlockedDecrement(&g_nSessionObjectsActive);
  580. }
  581. /*===================================================================
  582. CSession::Init
  583. Initialize CSession object
  584. Parameters:
  585. pAppln session's application to remember
  586. Id session id
  587. Returns:
  588. HRESULT
  589. ===================================================================*/
  590. HRESULT CSession::Init
  591. (
  592. CAppln *pAppln,
  593. const CSessionId &Id
  594. )
  595. {
  596. // Update global sessions counter
  597. InterlockedIncrement((LPLONG)&g_nSessions);
  598. #ifndef PERF_DISABLE
  599. g_PerfData.Incr_SESSIONCURRENT();
  600. g_PerfData.Incr_SESSIONSTOTAL();
  601. m_dwtInitTimestamp = GetTickCount();
  602. #endif
  603. // Setup the object
  604. HRESULT hr = S_OK;
  605. m_pAppln = pAppln;
  606. m_Id = Id;
  607. m_dwExternId = g_ExposedSessionIdGenerator.NewId();
  608. // Update application's session count
  609. m_pAppln->IncrementSessionCount();
  610. // default to system's ansi code page
  611. m_lCodePage = pAppln->QueryAppConfig()->uCodePage();
  612. m_lcid = pAppln->QueryAppConfig()->uLCID();
  613. // default session timeout
  614. m_nTimeout = pAppln->QueryAppConfig()->dwSessionTimeout();
  615. // initialize Viper activity
  616. if (SUCCEEDED(hr))
  617. hr = m_Activity.Init(pAppln->PServicesConfig());
  618. // mark as Inited and update timestamp
  619. if (SUCCEEDED(hr))
  620. m_fInited = TRUE;
  621. return hr;
  622. }
  623. /*===================================================================
  624. CSession::UnInit
  625. UnInitialize CSession object. Convert to tombstone state.
  626. Parameters:
  627. Returns:
  628. HRESULT (S_OK)
  629. ===================================================================*/
  630. HRESULT CSession::UnInit()
  631. {
  632. Assert(!m_fTombstone); // don't do it twice
  633. // Remove from timeout bucket if any
  634. if (m_fInTOBucket)
  635. m_pAppln->PSessionMgr()->RemoveSessionFromTOBucket(this);
  636. // Cleanup the object
  637. RemoveComponentCollection();
  638. // Get rid of the intrinsics
  639. m_Request.UnInit();
  640. m_Response.UnInit();
  641. m_Server.UnInit();
  642. // Get rid of Viper activity
  643. m_Activity.UnInit();
  644. // Update global counters
  645. #ifndef PERF_DISABLE
  646. if (m_fTimedOut)
  647. g_PerfData.Incr_SESSIONTIMEOUT();
  648. g_PerfData.Decr_SESSIONCURRENT();
  649. DWORD dwt = GetTickCount();
  650. if (dwt >= m_dwtInitTimestamp)
  651. dwt = dwt - m_dwtInitTimestamp;
  652. else
  653. dwt = (DWT_MAX - m_dwtInitTimestamp) + dwt;
  654. g_PerfData.Set_SESSIONLIFETIME(dwt);
  655. #endif
  656. m_pAppln->DecrementSessionCount();
  657. InterlockedDecrement((LPLONG)&g_nSessions);
  658. m_pAppln = NULL;
  659. m_pHitObj = NULL;
  660. // Mark this session as Tombstone
  661. m_fTombstone = TRUE;
  662. // Disconnect proxies NOW (in case we are in shutdown, or enter shutdown later & a proxy has a ref.)
  663. CoDisconnectObject(static_cast<ISessionObject *>(this), 0);
  664. return S_OK;
  665. }
  666. /*===================================================================
  667. CSession::MakeLightWeight
  668. Convert to 'light-weight' state if possible
  669. Parameters:
  670. Returns:
  671. HRESULT
  672. ===================================================================*/
  673. HRESULT CSession::MakeLightWeight()
  674. {
  675. Assert(m_fInited);
  676. if (m_fLightWeight)
  677. return S_OK;
  678. if (m_cRequests > 1) // requests pending for this session?
  679. return S_OK;
  680. if (m_fSessCompCol && !m_SessCompCol.FHasStateInfo())
  681. {
  682. // don't remove component collection from under enumerators
  683. if (!m_pTaggedObjects && !m_pProperties)
  684. RemoveComponentCollection();
  685. }
  686. m_fLightWeight = TRUE;
  687. return S_OK;
  688. }
  689. /*===================================================================
  690. CSession::CreateComponentCollection
  691. Create and Init Session's component collection.
  692. The actual object is aggregated by the session. Its state
  693. is controlled be m_fSessCompCol flag.
  694. Parameters:
  695. Returns:
  696. HRESULT
  697. ===================================================================*/
  698. HRESULT CSession::CreateComponentCollection()
  699. {
  700. Assert(!m_fSessCompCol);
  701. HRESULT hr = m_SessCompCol.Init(csSession);
  702. if (SUCCEEDED(hr))
  703. {
  704. m_fSessCompCol = TRUE;
  705. }
  706. else
  707. {
  708. RemoveComponentCollection();
  709. }
  710. return hr;
  711. }
  712. /*===================================================================
  713. CSession::RemoveComponentCollection
  714. Remove Session's component collection
  715. The actual object is aggregated by the session. Its state
  716. is controlled be m_fSessCompCol flag.
  717. Parameters:
  718. Returns:
  719. HRESULT
  720. ===================================================================*/
  721. HRESULT CSession::RemoveComponentCollection()
  722. {
  723. if (m_pTaggedObjects)
  724. {
  725. m_pTaggedObjects->UnInit();
  726. m_pTaggedObjects->Release();
  727. m_pTaggedObjects = NULL;
  728. }
  729. if (m_pProperties)
  730. {
  731. m_pProperties->UnInit();
  732. m_pProperties->Release();
  733. m_pProperties = NULL;
  734. }
  735. if (m_fSessCompCol)
  736. {
  737. m_SessCompCol.UnInit();
  738. m_fSessCompCol = FALSE;
  739. }
  740. return S_OK;
  741. }
  742. /*===================================================================
  743. CSession::FShouldBeDeletedNow
  744. Tests if the session should be deleted
  745. Parameters:
  746. BOOL fAtEndOfRequest TRUE if at the end of a request
  747. Returns:
  748. BOOL TRUE (should be deleted) or FALSE (shouldn't)
  749. ===================================================================*/
  750. BOOL CSession::FShouldBeDeletedNow
  751. (
  752. BOOL fAtEndOfRequest
  753. )
  754. {
  755. if (fAtEndOfRequest)
  756. {
  757. // Any OTHER requests pending -> don't delete
  758. if (m_cRequests > 1)
  759. return FALSE;
  760. }
  761. else
  762. {
  763. // Any requests pending -> don't delete
  764. if (m_cRequests > 0)
  765. return FALSE;
  766. }
  767. // GLOBAL.ASA changed - delete
  768. if (m_pAppln->FGlobalChanged())
  769. return TRUE;
  770. // Failed to start or abandoned - delete
  771. if (m_fOnStartFailed || m_fAbandoned)
  772. return TRUE;
  773. // Is stateless session? No need for Session_OnEnd?
  774. if (!m_fSessCompCol && // CompCol gone in MakeLightWeight()
  775. !m_fStateAcquired && // no other properties set
  776. !m_fOnStartInvoked && // on start was never invoked
  777. !m_fOnEndPresent) // on end is not present
  778. return TRUE; // -> delete this session
  779. // don't check timeout here
  780. return FALSE;
  781. }
  782. /*===================================================================
  783. CSession::QueryInterface
  784. QueryInterface() -- IUnknown implementation.
  785. Parameters:
  786. REFIID riid
  787. void **ppv
  788. Returns:
  789. HRESULT
  790. ===================================================================*/
  791. STDMETHODIMP CSession::QueryInterface
  792. (
  793. REFIID riid,
  794. void **ppv
  795. )
  796. {
  797. *ppv = NULL;
  798. if (IID_IUnknown == riid ||
  799. IID_IDispatch == riid ||
  800. IID_ISessionObject == riid ||
  801. IID_IDenaliIntrinsic == riid)
  802. {
  803. *ppv = static_cast<ISessionObject *>(this);
  804. ((IUnknown *)*ppv)->AddRef();
  805. return S_OK;
  806. }
  807. else if (IID_ISupportErrorInfo == riid)
  808. {
  809. m_ISuppErrImp.AddRef();
  810. *ppv = &m_ISuppErrImp;
  811. return S_OK;
  812. }
  813. else if (IID_IMarshal == riid)
  814. {
  815. *ppv = static_cast<IMarshal *>(this);
  816. ((IUnknown *)*ppv)->AddRef();
  817. return S_OK;
  818. }
  819. else
  820. {
  821. return E_NOINTERFACE;
  822. }
  823. }
  824. /*===================================================================
  825. CSession::AddRef
  826. AddRef() -- IUnknown implementation.
  827. Parameters:
  828. Returns:
  829. Ref count
  830. ===================================================================*/
  831. STDMETHODIMP_(ULONG) CSession::AddRef()
  832. {
  833. DWORD cRefs = InterlockedIncrement((LPLONG)&m_cRefs);
  834. IF_DEBUG(SESSION)
  835. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  836. return cRefs;
  837. }
  838. /*===================================================================
  839. CSession::Release
  840. Release() -- IUnknown implementation.
  841. Parameters:
  842. Returns:
  843. Ref count
  844. ===================================================================*/
  845. STDMETHODIMP_(ULONG) CSession::Release()
  846. {
  847. DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
  848. IF_DEBUG(SESSION)
  849. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  850. if (cRefs)
  851. return cRefs;
  852. delete this;
  853. return 0;
  854. }
  855. /*===================================================================
  856. CSession::CheckForTombstone
  857. Tombstone stub for ISessionObject methods. If the object is
  858. tombstone, does ExceptionId and fails.
  859. Parameters:
  860. Returns:
  861. HRESULT E_FAIL if Tombstone
  862. S_OK if not
  863. ===================================================================*/
  864. HRESULT CSession::CheckForTombstone()
  865. {
  866. if (!m_fTombstone)
  867. return S_OK;
  868. ExceptionId
  869. (
  870. IID_ISessionObject,
  871. IDE_SESSION,
  872. IDE_INTRINSIC_OUT_OF_SCOPE
  873. );
  874. return E_FAIL;
  875. }
  876. /*===================================================================
  877. CSession::get_SessionID
  878. ISessionObject implementation.
  879. Return the session ID to the caller
  880. Parameters:
  881. BSTR *pbstrRet [out] session id value
  882. Returns:
  883. HRESULT
  884. ===================================================================*/
  885. STDMETHODIMP CSession::get_SessionID
  886. (
  887. BSTR *pbstrRet
  888. )
  889. {
  890. if (FAILED(CheckForTombstone()))
  891. return E_FAIL;
  892. HRESULT hr = S_OK;
  893. wchar_t wszId[15];
  894. _ultow(m_dwExternId, wszId, 10);
  895. *pbstrRet = SysAllocString(wszId);
  896. if (*pbstrRet == NULL)
  897. {
  898. ExceptionId
  899. (
  900. IID_ISessionObject,
  901. IDE_SESSION_ID,
  902. IDE_SESSION_MAP_FAILED
  903. );
  904. hr = E_FAIL;
  905. }
  906. m_fStateAcquired = TRUE;
  907. return hr;
  908. }
  909. /*===================================================================
  910. CSession::get_Timeout
  911. ISessionObject implementation.
  912. Return the default or user set timeout interval (in minutes)
  913. Parameters:
  914. long *plVar [out] timeout value (in minutes)
  915. Returns:
  916. HRESULT
  917. ===================================================================*/
  918. STDMETHODIMP CSession::get_Timeout
  919. (
  920. long *plVar
  921. )
  922. {
  923. if (FAILED(CheckForTombstone()))
  924. return E_FAIL;
  925. *plVar = m_nTimeout;
  926. return S_OK;
  927. }
  928. /*===================================================================
  929. CSession::put_Timeout
  930. ISessionObject implementation.
  931. Allows the user to set the timeout interval (in minutes)
  932. Parameters:
  933. long lVar timeout value (in minutes)
  934. Returns:
  935. HRESULT
  936. ===================================================================*/
  937. STDMETHODIMP CSession::put_Timeout
  938. (
  939. long lVar
  940. )
  941. {
  942. if (FAILED(CheckForTombstone()))
  943. return E_FAIL;
  944. if (lVar < SESSION_TIMEOUT_MIN || lVar > SESSION_TIMEOUT_MAX)
  945. {
  946. ExceptionId
  947. (
  948. IID_ISessionObject,
  949. IDE_SESSION_ID,
  950. IDE_SESSION_INVALID_TIMEOUT
  951. );
  952. return E_FAIL;
  953. }
  954. m_fStateAcquired = TRUE;
  955. m_fCustomTimeout = TRUE;
  956. m_nTimeout = lVar;
  957. return S_OK;
  958. }
  959. /*===================================================================
  960. CSession::get_CodePage
  961. ISessionObject implementation.
  962. Returns the current code page value for the request
  963. Parameters:
  964. long *plVar [out] code page value
  965. Returns:
  966. HRESULT S_OK on success
  967. ===================================================================*/
  968. STDMETHODIMP CSession::get_CodePage
  969. (
  970. long *plVar
  971. )
  972. {
  973. if (FAILED(CheckForTombstone()))
  974. return E_FAIL;
  975. Assert(m_pHitObj);
  976. *plVar = m_lCodePage;
  977. // If code page is 0, look up default ANSI code page
  978. if (*plVar == 0)
  979. {
  980. *plVar = (long) GetACP();
  981. }
  982. return S_OK;
  983. }
  984. /*===================================================================
  985. CSession::put_CodePage
  986. ISessionObject implementation.
  987. Sets the current code page value for the request
  988. Parameters:
  989. long lVar code page to assign to this session
  990. Returns:
  991. HRESULT S_OK on success
  992. ===================================================================*/
  993. STDMETHODIMP CSession::put_CodePage
  994. (
  995. long lVar
  996. )
  997. {
  998. if (FAILED(CheckForTombstone()))
  999. return E_FAIL;
  1000. // set code page member variable
  1001. Assert(m_pHitObj);
  1002. HRESULT hr = m_pHitObj->SetCodePage(lVar);
  1003. if (FAILED(hr))
  1004. {
  1005. ExceptionId
  1006. (
  1007. IID_ISessionObject,
  1008. IDE_SESSION_ID,
  1009. IDE_SESSION_INVALID_CODEPAGE
  1010. );
  1011. return E_FAIL;
  1012. }
  1013. m_fCodePageSet = TRUE;
  1014. m_lCodePage = lVar;
  1015. // we need to preserve session since the user has set
  1016. // its code page member variable
  1017. m_fStateAcquired = TRUE;
  1018. return S_OK;
  1019. }
  1020. /*===================================================================
  1021. CSession::get_LCID
  1022. ISessionObject implementation.
  1023. Returns the current lcid value for the request
  1024. Parameters:
  1025. long *plVar [out] code page value
  1026. Returns:
  1027. HRESULT S_OK on success
  1028. ===================================================================*/
  1029. STDMETHODIMP CSession::get_LCID
  1030. (
  1031. long *plVar
  1032. )
  1033. {
  1034. if (FAILED(CheckForTombstone()))
  1035. return E_FAIL;
  1036. Assert(m_pHitObj);
  1037. *plVar = m_lcid;
  1038. if (*plVar == LOCALE_SYSTEM_DEFAULT) {
  1039. *plVar = GetSystemDefaultLCID();
  1040. }
  1041. return S_OK;
  1042. }
  1043. /*===================================================================
  1044. CSession::put_LCID
  1045. ISessionObject implementation.
  1046. Sets the current LCID value for the request
  1047. Parameters:
  1048. long lVar LCID to assign to this session
  1049. Returns:
  1050. HRESULT S_OK on success
  1051. ===================================================================*/
  1052. STDMETHODIMP CSession::put_LCID
  1053. (
  1054. long lVar
  1055. )
  1056. {
  1057. if (FAILED(CheckForTombstone()))
  1058. return E_FAIL;
  1059. // set code page member variable
  1060. Assert(m_pHitObj);
  1061. HRESULT hr = m_pHitObj->SetLCID(lVar);
  1062. if (FAILED(hr))
  1063. {
  1064. ExceptionId
  1065. (
  1066. IID_ISessionObject,
  1067. IDE_SESSION_ID,
  1068. IDE_TEMPLATE_BAD_LCID
  1069. );
  1070. return E_FAIL;
  1071. }
  1072. m_fLCIDSet = TRUE;
  1073. m_lcid = lVar;
  1074. // we need to preserve session since the user has set
  1075. // its lcid member variable
  1076. m_fStateAcquired = TRUE;
  1077. return S_OK;
  1078. }
  1079. /*===================================================================
  1080. CSession::get_Value
  1081. ISessionObject implementation.
  1082. Will allow the user to retreive a session state variable,
  1083. the variable will come as a named pair, bstr is the name and
  1084. var is the value or object to be returned for that name
  1085. Parameters:
  1086. BSTR bstrName Name of the variable to get
  1087. VARIANT *pVar Value/object to get for the variable
  1088. Returns:
  1089. HRESULT S_OK on success
  1090. ===================================================================*/
  1091. STDMETHODIMP CSession::get_Value
  1092. (
  1093. BSTR bstrName,
  1094. VARIANT *pVar
  1095. )
  1096. {
  1097. if (FAILED(CheckForTombstone()))
  1098. return E_FAIL;
  1099. if (bstrName == NULL)
  1100. {
  1101. ExceptionId(IID_ISessionObject, IDE_SESSION, IDE_EXPECTING_STR);
  1102. return E_FAIL;
  1103. }
  1104. VariantInit(pVar); // default variant empty
  1105. WCHAR *pwszName;
  1106. STACK_BUFFER(rgbName, 42);
  1107. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1108. if (pwszName == NULL)
  1109. return S_OK; // no name - no value - no error
  1110. //_wcsupr(pwszName);
  1111. CComponentObject *pObj = NULL;
  1112. HRESULT hr = S_OK;
  1113. Assert(m_pHitObj);
  1114. m_pHitObj->AssertValid();
  1115. hr = m_pHitObj->GetPropertyComponent(csSession, pwszName, &pObj);
  1116. if (SUCCEEDED(hr) && pObj)
  1117. hr = pObj->GetVariant(pVar);
  1118. return S_OK;
  1119. }
  1120. /*===================================================================
  1121. CSession::putref_Value
  1122. ISessionObject implementation.
  1123. Will allow the user to assign a session state variable to be saved
  1124. the variable will come as a named pair, bstr is the name and
  1125. var is the value or object to be stored for that name
  1126. Parameters:
  1127. BSTR bstrName Name of the variable to set
  1128. VARIANT Var Value/object to set for the variable
  1129. Returns:
  1130. HRESULT S_OK on success
  1131. ===================================================================*/
  1132. STDMETHODIMP CSession::putref_Value
  1133. (
  1134. BSTR bstrName,
  1135. VARIANT Var
  1136. )
  1137. {
  1138. if (FAILED(CheckForTombstone()))
  1139. return E_FAIL;
  1140. if (FIsIntrinsic(&Var))
  1141. {
  1142. ExceptionId(IID_ISessionObject, IDE_SESSION,
  1143. IDE_SESSION_CANT_STORE_INTRINSIC);
  1144. return E_FAIL;
  1145. }
  1146. if (bstrName == NULL)
  1147. {
  1148. ExceptionId(IID_ISessionObject, IDE_SESSION, IDE_EXPECTING_STR);
  1149. return E_FAIL;
  1150. }
  1151. HRESULT hr;
  1152. Assert(m_pHitObj);
  1153. m_pHitObj->AssertValid();
  1154. WCHAR *pwszName;
  1155. STACK_BUFFER(rgbName, 42);
  1156. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1157. if (pwszName == NULL)
  1158. {
  1159. ExceptionId
  1160. (
  1161. IID_ISessionObject,
  1162. IDE_SESSION,
  1163. IDE_EXPECTING_STR
  1164. );
  1165. return E_FAIL;
  1166. }
  1167. //_wcsupr(pwszName);
  1168. hr = m_pHitObj->SetPropertyComponent(csSession, pwszName, &Var);
  1169. return hr;
  1170. }
  1171. /*===================================================================
  1172. CSession::put_Value
  1173. ISessionObject implementation.
  1174. Implement property put by dereferencing variants before
  1175. calling putref.
  1176. Parameters:
  1177. BSTR bstrName Name of the variable to set
  1178. VARIANT Var Value/object to set for the variable
  1179. Returns:
  1180. HRESULT S_OK on success
  1181. ===================================================================*/
  1182. STDMETHODIMP CSession::put_Value
  1183. (
  1184. BSTR bstrName,
  1185. VARIANT Var
  1186. )
  1187. {
  1188. if (FAILED(CheckForTombstone()))
  1189. return E_FAIL;
  1190. if (bstrName == NULL)
  1191. {
  1192. ExceptionId(IID_ISessionObject, IDE_SESSION, IDE_EXPECTING_STR);
  1193. return E_FAIL;
  1194. }
  1195. HRESULT hr;
  1196. VARIANT varResolved;
  1197. hr = VariantResolveDispatch
  1198. (
  1199. &varResolved,
  1200. &Var,
  1201. IID_ISessionObject,
  1202. IDE_SESSION
  1203. );
  1204. if (FAILED(hr))
  1205. return hr; // exception already raised
  1206. Assert(m_pHitObj);
  1207. m_pHitObj->AssertValid();
  1208. WCHAR *pwszName;
  1209. STACK_BUFFER(rgbName, 42);
  1210. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1211. if (pwszName == NULL)
  1212. {
  1213. ExceptionId
  1214. (
  1215. IID_ISessionObject,
  1216. IDE_SESSION,
  1217. IDE_EXPECTING_STR
  1218. );
  1219. VariantClear( &varResolved );
  1220. return E_FAIL;
  1221. }
  1222. //_wcsupr(pwszName);
  1223. hr = m_pHitObj->SetPropertyComponent
  1224. (
  1225. csSession,
  1226. pwszName,
  1227. &varResolved
  1228. );
  1229. VariantClear( &varResolved );
  1230. return hr;
  1231. }
  1232. /*===================================================================
  1233. CSession::Abandon
  1234. ISessionObject implementation.
  1235. Abandon reassignes session id to avoid hitting this session
  1236. with incoming requests. Abandoned sessions get deleted ASAP.
  1237. Parameters:
  1238. None
  1239. Returns:
  1240. HRESULT S_OK on success
  1241. ===================================================================*/
  1242. STDMETHODIMP CSession::Abandon()
  1243. {
  1244. if (FAILED(CheckForTombstone()))
  1245. return E_FAIL;
  1246. m_fAbandoned = TRUE;
  1247. // The new session logic allows only one session id per
  1248. // client need to disassociate session from client
  1249. // (good idea when abandoning anyway)
  1250. Assert(m_pHitObj);
  1251. // If execution Session_OnEnd (not a browser request), do nothing
  1252. if (!m_pHitObj->FIsBrowserRequest())
  1253. return S_OK;
  1254. return m_pHitObj->ReassignAbandonedSession();
  1255. }
  1256. /*===================================================================
  1257. CSession::get_StaticObjects
  1258. Return the session static objects dictionary
  1259. ===================================================================*/
  1260. STDMETHODIMP CSession::get_StaticObjects
  1261. (
  1262. IVariantDictionary **ppDictReturn
  1263. )
  1264. {
  1265. if (FAILED(CheckForTombstone()))
  1266. return E_FAIL;
  1267. if (!m_pTaggedObjects)
  1268. {
  1269. m_pTaggedObjects = new CSessionVariants;
  1270. if (!m_pTaggedObjects)
  1271. return E_OUTOFMEMORY;
  1272. HRESULT hr = m_pTaggedObjects->Init(this, ctTagged);
  1273. if (FAILED(hr))
  1274. {
  1275. m_pTaggedObjects->UnInit();
  1276. m_pTaggedObjects->Release();
  1277. m_pTaggedObjects = NULL;
  1278. }
  1279. }
  1280. Assert(m_pTaggedObjects);
  1281. return m_pTaggedObjects->QueryInterface(IID_IVariantDictionary, reinterpret_cast<void **>(ppDictReturn));
  1282. }
  1283. /*===================================================================
  1284. CSession::get_Contents
  1285. Return the session contents dictionary
  1286. ===================================================================*/
  1287. STDMETHODIMP CSession::get_Contents
  1288. (
  1289. IVariantDictionary **ppDictReturn
  1290. )
  1291. {
  1292. if (FAILED(CheckForTombstone()))
  1293. return E_FAIL;
  1294. if (!m_pProperties)
  1295. {
  1296. m_pProperties = new CSessionVariants;
  1297. if (!m_pProperties)
  1298. return E_OUTOFMEMORY;
  1299. HRESULT hr = m_pProperties->Init(this, ctProperty);
  1300. if (FAILED(hr))
  1301. {
  1302. m_pProperties->UnInit();
  1303. m_pProperties->Release();
  1304. m_pProperties = NULL;
  1305. }
  1306. }
  1307. Assert(m_pProperties);
  1308. return m_pProperties->QueryInterface(IID_IVariantDictionary, reinterpret_cast<void **>(ppDictReturn));
  1309. }
  1310. #ifdef DBG
  1311. /*===================================================================
  1312. CSession::AssertValid
  1313. Test to make sure that the CSession object is currently
  1314. correctly formed and assert if it is not.
  1315. Returns:
  1316. None
  1317. Side effects:
  1318. None.
  1319. ===================================================================*/
  1320. VOID CSession::AssertValid() const
  1321. {
  1322. Assert(m_fInited);
  1323. if (!m_fTombstone)
  1324. Assert(m_pAppln);
  1325. }
  1326. #endif // DBG
  1327. /*===================================================================
  1328. C S e s s i o n M g r
  1329. ===================================================================*/
  1330. /*===================================================================
  1331. CSessionMgr::CSessionMgr
  1332. CSessionMgr constructor.
  1333. Parameters:
  1334. NONE
  1335. Returns:
  1336. ===================================================================*/
  1337. CSessionMgr::CSessionMgr()
  1338. :
  1339. m_fInited(FALSE),
  1340. m_pAppln(NULL),
  1341. m_cSessionCleanupRequests(0),
  1342. m_cTimeoutBuckets(0),
  1343. m_rgolTOBuckets(NULL),
  1344. m_idSessionKiller(0),
  1345. m_dwmCurrentTime(0),
  1346. m_dwtNextSessionKillerTime(0)
  1347. {
  1348. }
  1349. /*===================================================================
  1350. CSessionMgr::~CSessionMgr
  1351. CSessionMgr destructor.
  1352. Parameters:
  1353. NONE
  1354. Returns:
  1355. ===================================================================*/
  1356. CSessionMgr::~CSessionMgr()
  1357. {
  1358. UnInit();
  1359. }
  1360. /*===================================================================
  1361. HRESULT CSessionMgr::Init
  1362. Initializes the Session Manager.
  1363. Initializes hash tables.
  1364. Schedules session killer.
  1365. Parameters:
  1366. pAppln Application
  1367. Returns:
  1368. HRESULT
  1369. ===================================================================*/
  1370. HRESULT CSessionMgr::Init
  1371. (
  1372. CAppln *pAppln
  1373. )
  1374. {
  1375. Assert(!m_fInited);
  1376. HRESULT hr;
  1377. m_pAppln = pAppln;
  1378. // Master hash table
  1379. hr = m_htidMaster.Init
  1380. (
  1381. SESSION_MASTERHASH_SIZE1_MAX,
  1382. SESSION_MASTERHASH_SIZE2_MAX,
  1383. SESSION_MASTERHASH_SIZE3_MAX
  1384. );
  1385. if (FAILED(hr))
  1386. return hr;
  1387. // Number of timeout buckets = session timeout in minutes + 1
  1388. m_cTimeoutBuckets =
  1389. m_pAppln->QueryAppConfig()->dwSessionTimeout() + 1;
  1390. if (m_cTimeoutBuckets < SESSION_TIMEOUTBUCKETS_MIN)
  1391. m_cTimeoutBuckets = SESSION_TIMEOUTBUCKETS_MIN;
  1392. else if (m_cTimeoutBuckets > SESSION_TIMEOUTBUCKETS_MAX)
  1393. m_cTimeoutBuckets = SESSION_TIMEOUTBUCKETS_MAX;
  1394. // Timeout buckets hash tables array
  1395. m_rgolTOBuckets = new CObjectListWithLock[m_cTimeoutBuckets];
  1396. if (!m_rgolTOBuckets)
  1397. return E_OUTOFMEMORY;
  1398. // Each timeout bucket hash table
  1399. for (DWORD i = 0; i < m_cTimeoutBuckets; i++)
  1400. {
  1401. hr = m_rgolTOBuckets[i].Init
  1402. (
  1403. OBJECT_LIST_ELEM_FIELD_OFFSET(CSession, m_TOBucketElem)
  1404. );
  1405. if (FAILED(hr))
  1406. return hr;
  1407. }
  1408. // Schedule session killer
  1409. hr = ScheduleSessionKiller();
  1410. if (FAILED(hr))
  1411. return hr;
  1412. // Start counting time
  1413. m_dwmCurrentTime = 0;
  1414. // Remember the time of the next session killer
  1415. m_dwtNextSessionKillerTime = ::GetTickCount() + MSEC_ONE_MINUTE;
  1416. m_fInited = TRUE;
  1417. return S_OK;
  1418. }
  1419. /*===================================================================
  1420. HRESULT CSessionMgr::UnInit
  1421. UnInitializes the Session Manager.
  1422. Parameters:
  1423. Returns:
  1424. S_OK
  1425. ===================================================================*/
  1426. HRESULT CSessionMgr::UnInit( void )
  1427. {
  1428. // Un-schedule session killer
  1429. if (m_idSessionKiller)
  1430. UnScheduleSessionKiller();
  1431. // Timeout buckets
  1432. if (m_rgolTOBuckets)
  1433. {
  1434. for (DWORD i = 0; i < m_cTimeoutBuckets; i++)
  1435. m_rgolTOBuckets[i].UnInit();
  1436. delete [] m_rgolTOBuckets;
  1437. m_rgolTOBuckets = NULL;
  1438. }
  1439. m_cTimeoutBuckets = 0;
  1440. // Master hash
  1441. m_htidMaster.UnInit();
  1442. m_fInited = FALSE;
  1443. return S_OK;
  1444. }
  1445. /*===================================================================
  1446. CSessionMgr::ScheduleSessionKiller
  1447. Sets up the session killer workitem for ATQ scheduler
  1448. Parameters:
  1449. Returns:
  1450. HRESULT
  1451. ===================================================================*/
  1452. HRESULT CSessionMgr::ScheduleSessionKiller()
  1453. {
  1454. Assert(!m_idSessionKiller);
  1455. m_idSessionKiller = ScheduleWorkItem
  1456. (
  1457. CSessionMgr::SessionKillerSchedulerCallback, // callback
  1458. this, // context
  1459. MSEC_ONE_MINUTE, // timeout
  1460. TRUE // periodic
  1461. );
  1462. return m_idSessionKiller ? S_OK : E_FAIL;
  1463. }
  1464. /*===================================================================
  1465. CSessionMgr::UnScheduleSessionKiller
  1466. Removes the session killer workitem for ATQ scheduler
  1467. Parameters:
  1468. Returns:
  1469. S_OK
  1470. ===================================================================*/
  1471. HRESULT CSessionMgr::UnScheduleSessionKiller()
  1472. {
  1473. if (m_idSessionKiller)
  1474. {
  1475. RemoveWorkItem(m_idSessionKiller);
  1476. m_idSessionKiller = 0;
  1477. }
  1478. return S_OK;
  1479. }
  1480. /*===================================================================
  1481. CSessionMgr::GenerateIdAndCookie
  1482. Generate new ID and cookie to be used create new session
  1483. or reassign the session ID for an existing session.
  1484. Parameters:
  1485. pId [out] ID
  1486. pszNewCookie [out] Cookie (buf must be long enough)
  1487. Returns:
  1488. S_OK
  1489. ===================================================================*/
  1490. HRESULT CSessionMgr::GenerateIdAndCookie
  1491. (
  1492. CSessionId *pId,
  1493. char *pszNewCookie
  1494. )
  1495. {
  1496. pId->m_dwId = g_SessionIdGenerator.NewId();
  1497. GenerateRandomDwords(&pId->m_dwR1, 2);
  1498. EncodeSessionIdCookie
  1499. (
  1500. pId->m_dwId,
  1501. pId->m_dwR1,
  1502. pId->m_dwR2,
  1503. pszNewCookie
  1504. );
  1505. return S_OK;
  1506. }
  1507. /*===================================================================
  1508. CSessionMgr::NewSession
  1509. Creates and Inits a new CSession object
  1510. Parameters:
  1511. Id session id
  1512. ppSession [out] session created
  1513. Returns:
  1514. HRESULT
  1515. ===================================================================*/
  1516. HRESULT CSessionMgr::NewSession
  1517. (
  1518. const CSessionId &Id,
  1519. CSession **ppSession
  1520. )
  1521. {
  1522. Assert(m_fInited);
  1523. HRESULT hr = S_OK;
  1524. CSession *pSession = new CSession;
  1525. if (!pSession)
  1526. hr = E_OUTOFMEMORY;
  1527. if (SUCCEEDED(hr))
  1528. hr = pSession->Init(m_pAppln, Id);
  1529. if (SUCCEEDED(hr))
  1530. {
  1531. Assert(pSession);
  1532. *ppSession = pSession;
  1533. }
  1534. else
  1535. {
  1536. // failed - do cleanup
  1537. if (pSession)
  1538. {
  1539. pSession->UnInit();
  1540. pSession->Release();
  1541. }
  1542. *ppSession = NULL;
  1543. }
  1544. return hr;
  1545. }
  1546. /*===================================================================
  1547. CSessionMgr::ChangeSessionId
  1548. Reassigns different session Id to a session.
  1549. Updates the master hash.
  1550. This method is called when abandoning a session
  1551. to disassociate it from the client.
  1552. Parameters:
  1553. pSession session to change id on
  1554. Id new session id to assign
  1555. Returns:
  1556. S_OK on success
  1557. E_FAIL on failure
  1558. ===================================================================*/
  1559. HRESULT CSessionMgr::ChangeSessionId
  1560. (
  1561. CSession *pSession,
  1562. const CSessionId &Id
  1563. )
  1564. {
  1565. HRESULT hr;
  1566. // During request processing session's not supposed to be
  1567. // in any timeout bucket
  1568. Assert(!pSession->m_fInTOBucket);
  1569. LockMaster();
  1570. // Remove from master hash by Id
  1571. hr = RemoveFromMasterHash(pSession);
  1572. if (SUCCEEDED(hr))
  1573. {
  1574. // Assign new id
  1575. pSession->AssignNewId(Id);
  1576. // Reinsert into master hash by id
  1577. hr = AddToMasterHash(pSession);
  1578. }
  1579. UnLockMaster();
  1580. return hr;
  1581. }
  1582. /*===================================================================
  1583. CSessionMgr::FindInMasterHash
  1584. Finds Session in master hash session id.
  1585. Doesn't Lock.
  1586. Parameters:
  1587. Id session id to find
  1588. **ppSession [out] session found
  1589. Returns:
  1590. S_OK good session found
  1591. S_FALSE session not found or bad session found
  1592. ===================================================================*/
  1593. HRESULT CSessionMgr::FindInMasterHash
  1594. (
  1595. const CSessionId &Id,
  1596. CSession **ppSession
  1597. )
  1598. {
  1599. Assert(m_fInited);
  1600. // Find in the hash table
  1601. HRESULT hr = m_htidMaster.FindObject(Id.m_dwId, (void **)ppSession);
  1602. if (hr != S_OK)
  1603. {
  1604. // Not found
  1605. *ppSession = NULL;
  1606. return hr;
  1607. }
  1608. // Session found, check if valid
  1609. if ((*ppSession)->m_fAbandoned ||
  1610. (*ppSession)->m_fTombstone ||
  1611. !(*ppSession)->FPassesIdSecurityCheck(Id.m_dwR1, Id.m_dwR2))
  1612. {
  1613. // Bad session
  1614. hr = S_FALSE;
  1615. }
  1616. return hr;
  1617. }
  1618. /*===================================================================
  1619. CSessionMgr::AddSessionToTOBucket
  1620. Adds session to the correct timeout bucket.
  1621. Locks the timeout bucket.
  1622. Parameters:
  1623. pSession - session to add
  1624. Returns:
  1625. HRESULT
  1626. ===================================================================*/
  1627. HRESULT CSessionMgr::AddSessionToTOBucket
  1628. (
  1629. CSession *pSession
  1630. )
  1631. {
  1632. HRESULT hr;
  1633. // Should not be already in a timeout bucket
  1634. Assert(!pSession->m_fInTOBucket);
  1635. DWORD iBucket = GetSessionTOBucket(pSession);
  1636. LockTOBucket(iBucket);
  1637. hr = m_rgolTOBuckets[iBucket].AddObject(pSession);
  1638. if (SUCCEEDED(hr))
  1639. pSession->m_fInTOBucket = TRUE;
  1640. UnLockTOBucket(iBucket);
  1641. return hr;
  1642. }
  1643. /*===================================================================
  1644. CSessionMgr::RemoveSessionToTOBucket
  1645. Removes from its timeout bucket if any.
  1646. Locks the timeout bucket.
  1647. Parameters:
  1648. pSession - session to remove
  1649. fLock - lock bucket? (not needed during shutdown)
  1650. Returns:
  1651. HRESULT
  1652. ===================================================================*/
  1653. HRESULT CSessionMgr::RemoveSessionFromTOBucket
  1654. (
  1655. CSession *pSession,
  1656. BOOL fLock
  1657. )
  1658. {
  1659. HRESULT hr;
  1660. Assert(m_fInited);
  1661. Assert(pSession->m_fInited);
  1662. if (!pSession->m_fInTOBucket) // not there - no error
  1663. return S_OK;
  1664. DWORD iBucket = GetSessionTOBucket(pSession);
  1665. if (fLock)
  1666. LockTOBucket(iBucket);
  1667. if (pSession->m_fInTOBucket) // recheck after locking
  1668. hr = m_rgolTOBuckets[iBucket].RemoveObject(pSession);
  1669. else
  1670. hr = S_OK;
  1671. if (SUCCEEDED(hr))
  1672. pSession->m_fInTOBucket = FALSE;
  1673. if (fLock)
  1674. UnLockTOBucket(iBucket);
  1675. return hr;
  1676. }
  1677. /*===================================================================
  1678. CSessionMgr::DeleteSession
  1679. Delete now or post for deletion.
  1680. Should be called after the session is gone from the hash table
  1681. Parameters:
  1682. CSession *pSession - session to release
  1683. BOOL fInSessionActivity - TRUE when deleting HitObj's session
  1684. at the end of request (no Async
  1685. calls needed)
  1686. Returns:
  1687. HRESULT (S_OK)
  1688. ===================================================================*/
  1689. HRESULT CSessionMgr::DeleteSession
  1690. (
  1691. CSession *pSession,
  1692. BOOL fInSessionActivity
  1693. )
  1694. {
  1695. Assert(pSession);
  1696. pSession->AssertValid();
  1697. // Take care of DELETE NOW case
  1698. BOOL fDeleteNow = pSession->FCanDeleteWithoutExec();
  1699. // If called not from the session's activity and session
  1700. // has objects then need to switch to the right activity
  1701. // to remove the session level objects
  1702. if (!fInSessionActivity && pSession->FHasObjects())
  1703. fDeleteNow = FALSE;
  1704. if (fDeleteNow)
  1705. {
  1706. pSession->UnInit();
  1707. pSession->Release();
  1708. return S_OK;
  1709. }
  1710. // THE ASYNC DELETE LOGIC
  1711. HRESULT hr = S_OK;
  1712. // Make sure session object exists after AsyncCall
  1713. pSession->AddRef();
  1714. // Create new HitObj and init it for session delete
  1715. CHitObj *pHitObj = new CHitObj;
  1716. if (pHitObj)
  1717. {
  1718. pHitObj->SessionCleanupInit(pSession);
  1719. if (fInSessionActivity)
  1720. {
  1721. // Already inside the correct activity no need to
  1722. // push the call through Viper
  1723. BOOL fRequestReposted = FALSE;
  1724. pHitObj->ViperAsyncCallback(&fRequestReposted);
  1725. Assert(!fRequestReposted); // this better not happen
  1726. delete pHitObj;
  1727. }
  1728. else
  1729. {
  1730. // Ask Viper to post the request
  1731. hr = pHitObj->PostViperAsyncCall();
  1732. if (FAILED(hr))
  1733. delete pHitObj;
  1734. }
  1735. }
  1736. else
  1737. {
  1738. hr = E_OUTOFMEMORY;
  1739. }
  1740. if (FAILED(hr))
  1741. {
  1742. // Out of memery or Viper failed to post a request
  1743. // Force the issue inside TRY CATCH
  1744. // (not always safe to delete in the wrong thread)
  1745. TRY
  1746. hr = pSession->UnInit();
  1747. CATCH(nExcept)
  1748. pSession->m_fTombstone = TRUE;
  1749. CoDisconnectObject(static_cast<ISessionObject *>(pSession), 0);
  1750. hr = E_UNEXPECTED;
  1751. END_TRY
  1752. pSession->Release();
  1753. }
  1754. pSession->Release(); // Undo AddRef()
  1755. return S_OK;
  1756. }
  1757. /*===================================================================
  1758. CSessionMgr::DeleteExpiredSessions
  1759. Removes expired Sessions from a given timeout bucket
  1760. Parameters:
  1761. iBucket timeout bucket #
  1762. Returns:
  1763. HRESULT (S_OK)
  1764. ===================================================================*/
  1765. HRESULT CSessionMgr::DeleteExpiredSessions
  1766. (
  1767. DWORD iBucket
  1768. )
  1769. {
  1770. LockTOBucket(iBucket);
  1771. void *pvSession = m_rgolTOBuckets[iBucket].PFirstObject();
  1772. while (pvSession && !IsShutDownInProgress())
  1773. {
  1774. CSession *pSession = reinterpret_cast<CSession *>(pvSession);
  1775. pvSession = m_rgolTOBuckets[iBucket].PNextObject(pvSession);
  1776. if (pSession->GetRequestsCount() == 0)
  1777. {
  1778. BOOL fTimedOut = pSession->GetTimeoutTime() <= GetCurrentTime();
  1779. BOOL fRemovedFromMasterHash = FALSE;
  1780. if (fTimedOut || pSession->FShouldBeDeletedNow(FALSE))
  1781. {
  1782. LockMaster();
  1783. if (pSession->GetRequestsCount() == 0) // recheck after lock
  1784. {
  1785. RemoveFromMasterHash(pSession);
  1786. fRemovedFromMasterHash = TRUE;
  1787. }
  1788. UnLockMaster();
  1789. }
  1790. if (fRemovedFromMasterHash)
  1791. {
  1792. if (fTimedOut)
  1793. pSession->m_fTimedOut = TRUE;
  1794. // delete from timeout bucket
  1795. m_rgolTOBuckets[iBucket].RemoveObject(pSession);
  1796. pSession->m_fInTOBucket = FALSE;
  1797. // delete session object itself (or schedule for deletion)
  1798. DeleteSession(pSession);
  1799. }
  1800. }
  1801. }
  1802. UnLockTOBucket(iBucket);
  1803. return S_OK;
  1804. }
  1805. /*===================================================================
  1806. CSessionMgr::DeleteAllSessions
  1807. Application shutdown code.
  1808. Parameters:
  1809. fForce flag - force delete?
  1810. Returns:
  1811. HRESULT (S_OK)
  1812. ===================================================================*/
  1813. HRESULT CSessionMgr::DeleteAllSessions
  1814. (
  1815. BOOL fForce
  1816. )
  1817. {
  1818. // Remove session killer so that it wouldn't interfere
  1819. UnScheduleSessionKiller();
  1820. LockMaster();
  1821. HRESULT hr = m_htidMaster.IterateObjects
  1822. (
  1823. DeleteAllSessionsCB,
  1824. this,
  1825. &fForce
  1826. );
  1827. if (fForce)
  1828. m_htidMaster.RemoveAllObjects();
  1829. UnLockMaster();
  1830. return hr;
  1831. }
  1832. /*===================================================================
  1833. CSessionMgr::DeleteAllSessionsCB
  1834. Static iterator callback.
  1835. Removes Session regardless.
  1836. Parameters:
  1837. pvSession session passed as void*
  1838. pvSessionMgr session manager passed as void*
  1839. pvfForce flag if TRUE - force the issue
  1840. Returns:
  1841. IteratorCallbackCode
  1842. ===================================================================*/
  1843. IteratorCallbackCode CSessionMgr::DeleteAllSessionsCB
  1844. (
  1845. void *pvSession,
  1846. void *pvSessionMgr,
  1847. void *pvfForce
  1848. )
  1849. {
  1850. IteratorCallbackCode rc = iccContinue;
  1851. CSession *pSession = reinterpret_cast<CSession *>(pvSession);
  1852. CSessionMgr *pMgr = reinterpret_cast<CSessionMgr *>(pvSessionMgr);
  1853. BOOL fForce = *(reinterpret_cast<BOOL *>(pvfForce));
  1854. // Try for 5 seconds to post delete for each session
  1855. for (int iT = 0; iT < 10; iT++)
  1856. {
  1857. if (pSession->GetRequestsCount() == 0)
  1858. {
  1859. if (fForce)
  1860. {
  1861. // When forcing delete and there are too many
  1862. // session cleanup requests quequed
  1863. // wait for the queue to drain
  1864. while (pMgr->GetNumSessionCleanupRequests() >= SUGGESTED_SESSION_CLEANUP_REQUESTS_MAX)
  1865. Sleep(100);
  1866. }
  1867. else // if (!fForce)
  1868. {
  1869. // When not forcing delete (on application restart)
  1870. // don't queue too many sessions at one time
  1871. if (pMgr->GetNumSessionCleanupRequests() < SUGGESTED_SESSION_CLEANUP_REQUESTS_MAX)
  1872. rc = iccRemoveAndContinue;
  1873. else
  1874. rc = iccRemoveAndStop;
  1875. }
  1876. if (pSession->FInTOBucket())
  1877. pMgr->RemoveSessionFromTOBucket(pSession, !fForce);
  1878. pMgr->DeleteSession(pSession);
  1879. break;
  1880. }
  1881. if (!fForce)
  1882. break;
  1883. Sleep(500);
  1884. }
  1885. return rc;
  1886. }
  1887. /*===================================================================
  1888. CSessionMgr::SessionKillerSchedulerCallback
  1889. Static method implements ATQ scheduler callback functions.
  1890. Replaces session killer thread
  1891. Parameters:
  1892. void *pv context pointer (points to appl)
  1893. Returns:
  1894. Side effects:
  1895. None.
  1896. ===================================================================*/
  1897. void WINAPI CSessionMgr::SessionKillerSchedulerCallback
  1898. (
  1899. void *pv
  1900. )
  1901. {
  1902. if (IsShutDownInProgress())
  1903. return;
  1904. Assert(pv);
  1905. CSessionMgr *pMgr = reinterpret_cast<CSessionMgr *>(pv);
  1906. // Advance session killer time by 1 [minute]
  1907. pMgr->m_dwmCurrentTime++;
  1908. // Choose the bucket
  1909. DWORD iBucket = pMgr->m_dwmCurrentTime % pMgr->m_cTimeoutBuckets;
  1910. // Kill the sessions
  1911. pMgr->DeleteExpiredSessions(iBucket);
  1912. // Adjust the timeout to stay on the minute boundary
  1913. pMgr->m_dwtNextSessionKillerTime += MSEC_ONE_MINUTE;
  1914. // Calculate wait till next callback wakes up
  1915. DWORD dwtCur = ::GetTickCount();
  1916. DWORD dwtWait = 5000; // 5 sec if we are already late
  1917. // if (dwtCur < pMgr->m_dwtNextSessionKillerTime)
  1918. // {
  1919. dwtWait = pMgr->m_dwtNextSessionKillerTime - dwtCur;
  1920. if (dwtWait > MSEC_ONE_MINUTE)
  1921. dwtWait = MSEC_ONE_MINUTE; // in case of wrap-around
  1922. // }
  1923. ScheduleAdjustTime(pMgr->m_idSessionKiller, dwtWait);
  1924. }
  1925. #ifdef DBG
  1926. /*===================================================================
  1927. CSessionMgr::AssertValid
  1928. Test to make sure that this is currently correctly formed
  1929. and assert if it is not.
  1930. Returns:
  1931. ===================================================================*/
  1932. void CSessionMgr::AssertValid() const
  1933. {
  1934. Assert(m_fInited);
  1935. }
  1936. #endif