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.

2463 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_ISuppErrImp.Init(static_cast<ISessionObject *>(this),
  561. static_cast<ISessionObject *>(this),
  562. IID_ISessionObject);
  563. CDispatch::Init(IID_ISessionObject);
  564. InterlockedIncrement(&g_nSessionObjectsActive);
  565. IF_DEBUG(SESSION)
  566. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  567. }
  568. /*===================================================================
  569. CSession::~CSession
  570. Destructor
  571. Parameters:
  572. Returns:
  573. ===================================================================*/
  574. CSession::~CSession()
  575. {
  576. Assert(m_fTombstone); // must be tombstoned before destructor
  577. Assert(m_cRefs == 0); // must have 0 ref count
  578. InterlockedDecrement(&g_nSessionObjectsActive);
  579. }
  580. /*===================================================================
  581. CSession::Init
  582. Initialize CSession object
  583. Parameters:
  584. pAppln session's application to remember
  585. Id session id
  586. Returns:
  587. HRESULT
  588. ===================================================================*/
  589. HRESULT CSession::Init
  590. (
  591. CAppln *pAppln,
  592. const CSessionId &Id
  593. )
  594. {
  595. // Update global sessions counter
  596. InterlockedIncrement((LPLONG)&g_nSessions);
  597. #ifndef PERF_DISABLE
  598. g_PerfData.Incr_SESSIONCURRENT();
  599. g_PerfData.Incr_SESSIONSTOTAL();
  600. m_dwtInitTimestamp = GetTickCount();
  601. #endif
  602. // Setup the object
  603. HRESULT hr = S_OK;
  604. m_pAppln = pAppln;
  605. m_Id = Id;
  606. m_dwExternId = g_ExposedSessionIdGenerator.NewId();
  607. // Update application's session count
  608. m_pAppln->IncrementSessionCount();
  609. // default to system's ansi code page
  610. m_lCodePage = pAppln->QueryAppConfig()->uCodePage();
  611. m_lcid = pAppln->QueryAppConfig()->uLCID();
  612. // default session timeout
  613. m_nTimeout = pAppln->QueryAppConfig()->dwSessionTimeout();
  614. // initialize Viper activity
  615. if (SUCCEEDED(hr))
  616. hr = m_Activity.Init(pAppln->QueryAppConfig()->fExecuteInMTA());
  617. // mark as Inited and update timestamp
  618. if (SUCCEEDED(hr))
  619. m_fInited = TRUE;
  620. return hr;
  621. }
  622. /*===================================================================
  623. CSession::UnInit
  624. UnInitialize CSession object. Convert to tombstone state.
  625. Parameters:
  626. Returns:
  627. HRESULT (S_OK)
  628. ===================================================================*/
  629. HRESULT CSession::UnInit()
  630. {
  631. Assert(!m_fTombstone); // don't do it twice
  632. // Remove from timeout bucket if any
  633. if (m_fInTOBucket)
  634. m_pAppln->PSessionMgr()->RemoveSessionFromTOBucket(this);
  635. // Cleanup the object
  636. RemoveComponentCollection();
  637. // Get rid of the intrinsics
  638. m_Request.UnInit();
  639. m_Response.UnInit();
  640. m_Server.UnInit();
  641. // Get rid of Viper activity
  642. m_Activity.UnInit();
  643. // Update global counters
  644. #ifndef PERF_DISABLE
  645. if (m_fTimedOut)
  646. g_PerfData.Incr_SESSIONTIMEOUT();
  647. g_PerfData.Decr_SESSIONCURRENT();
  648. DWORD dwt = GetTickCount();
  649. if (dwt >= m_dwtInitTimestamp)
  650. dwt = dwt - m_dwtInitTimestamp;
  651. else
  652. dwt = (DWT_MAX - m_dwtInitTimestamp) + dwt;
  653. g_PerfData.Set_SESSIONLIFETIME(dwt);
  654. #endif
  655. m_pAppln->DecrementSessionCount();
  656. InterlockedDecrement((LPLONG)&g_nSessions);
  657. m_pAppln = NULL;
  658. m_pHitObj = NULL;
  659. // Mark this session as Tombstone
  660. m_fTombstone = TRUE;
  661. // Disconnect proxies NOW (in case we are in shutdown, or enter shutdown later & a proxy has a ref.)
  662. CoDisconnectObject(static_cast<ISessionObject *>(this), 0);
  663. return S_OK;
  664. }
  665. /*===================================================================
  666. CSession::MakeLightWeight
  667. Convert to 'light-weight' state if possible
  668. Parameters:
  669. Returns:
  670. HRESULT
  671. ===================================================================*/
  672. HRESULT CSession::MakeLightWeight()
  673. {
  674. Assert(m_fInited);
  675. if (m_fLightWeight)
  676. return S_OK;
  677. if (m_cRequests > 1) // requests pending for this session?
  678. return S_OK;
  679. if (m_fSessCompCol && !m_SessCompCol.FHasStateInfo())
  680. {
  681. // don't remove component collection from under enumerators
  682. if (!m_pTaggedObjects && !m_pProperties)
  683. RemoveComponentCollection();
  684. }
  685. m_fLightWeight = TRUE;
  686. return S_OK;
  687. }
  688. /*===================================================================
  689. CSession::CreateComponentCollection
  690. Create and Init Session's component collection.
  691. The actual object is aggregated by the session. Its state
  692. is controlled be m_fSessCompCol flag.
  693. Parameters:
  694. Returns:
  695. HRESULT
  696. ===================================================================*/
  697. HRESULT CSession::CreateComponentCollection()
  698. {
  699. Assert(!m_fSessCompCol);
  700. HRESULT hr = m_SessCompCol.Init(csSession);
  701. if (SUCCEEDED(hr))
  702. {
  703. m_fSessCompCol = TRUE;
  704. }
  705. else
  706. {
  707. RemoveComponentCollection();
  708. }
  709. return hr;
  710. }
  711. /*===================================================================
  712. CSession::RemoveComponentCollection
  713. Remove Session's component collection
  714. The actual object is aggregated by the session. Its state
  715. is controlled be m_fSessCompCol flag.
  716. Parameters:
  717. Returns:
  718. HRESULT
  719. ===================================================================*/
  720. HRESULT CSession::RemoveComponentCollection()
  721. {
  722. if (m_pTaggedObjects)
  723. {
  724. m_pTaggedObjects->UnInit();
  725. m_pTaggedObjects->Release();
  726. m_pTaggedObjects = NULL;
  727. }
  728. if (m_pProperties)
  729. {
  730. m_pProperties->UnInit();
  731. m_pProperties->Release();
  732. m_pProperties = NULL;
  733. }
  734. if (m_fSessCompCol)
  735. {
  736. m_SessCompCol.UnInit();
  737. m_fSessCompCol = FALSE;
  738. }
  739. return S_OK;
  740. }
  741. /*===================================================================
  742. CSession::FShouldBeDeletedNow
  743. Tests if the session should be deleted
  744. Parameters:
  745. BOOL fAtEndOfRequest TRUE if at the end of a request
  746. Returns:
  747. BOOL TRUE (should be deleted) or FALSE (shouldn't)
  748. ===================================================================*/
  749. BOOL CSession::FShouldBeDeletedNow
  750. (
  751. BOOL fAtEndOfRequest
  752. )
  753. {
  754. if (fAtEndOfRequest)
  755. {
  756. // Any OTHER requests pending -> don't delete
  757. if (m_cRequests > 1)
  758. return FALSE;
  759. }
  760. else
  761. {
  762. // Any requests pending -> don't delete
  763. if (m_cRequests > 0)
  764. return FALSE;
  765. }
  766. // GLOBAL.ASA changed - delete
  767. if (m_pAppln->FGlobalChanged())
  768. return TRUE;
  769. // Failed to start or abandoned - delete
  770. if (m_fOnStartFailed || m_fAbandoned)
  771. return TRUE;
  772. // Is stateless session? No need for Session_OnEnd?
  773. if (!m_fSessCompCol && // CompCol gone in MakeLightWeight()
  774. !m_fStateAcquired && // no other properties set
  775. !m_fOnStartInvoked && // on start was never invoked
  776. !m_fOnEndPresent) // on end is not present
  777. return TRUE; // -> delete this session
  778. // don't check timeout here
  779. return FALSE;
  780. }
  781. /*===================================================================
  782. CSession::QueryInterface
  783. QueryInterface() -- IUnknown implementation.
  784. Parameters:
  785. REFIID riid
  786. void **ppv
  787. Returns:
  788. HRESULT
  789. ===================================================================*/
  790. STDMETHODIMP CSession::QueryInterface
  791. (
  792. REFIID riid,
  793. void **ppv
  794. )
  795. {
  796. *ppv = NULL;
  797. if (IID_IUnknown == riid ||
  798. IID_IDispatch == riid ||
  799. IID_ISessionObject == riid ||
  800. IID_IDenaliIntrinsic == riid)
  801. {
  802. *ppv = static_cast<ISessionObject *>(this);
  803. ((IUnknown *)*ppv)->AddRef();
  804. return S_OK;
  805. }
  806. else if (IID_ISupportErrorInfo == riid)
  807. {
  808. m_ISuppErrImp.AddRef();
  809. *ppv = &m_ISuppErrImp;
  810. return S_OK;
  811. }
  812. else if (IID_IMarshal == riid)
  813. {
  814. *ppv = static_cast<IMarshal *>(this);
  815. ((IUnknown *)*ppv)->AddRef();
  816. return S_OK;
  817. }
  818. else
  819. {
  820. return E_NOINTERFACE;
  821. }
  822. }
  823. /*===================================================================
  824. CSession::AddRef
  825. AddRef() -- IUnknown implementation.
  826. Parameters:
  827. Returns:
  828. Ref count
  829. ===================================================================*/
  830. STDMETHODIMP_(ULONG) CSession::AddRef()
  831. {
  832. DWORD cRefs = InterlockedIncrement((LPLONG)&m_cRefs);
  833. IF_DEBUG(SESSION)
  834. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  835. return cRefs;
  836. }
  837. /*===================================================================
  838. CSession::Release
  839. Release() -- IUnknown implementation.
  840. Parameters:
  841. Returns:
  842. Ref count
  843. ===================================================================*/
  844. STDMETHODIMP_(ULONG) CSession::Release()
  845. {
  846. DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
  847. IF_DEBUG(SESSION)
  848. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  849. if (cRefs)
  850. return cRefs;
  851. delete this;
  852. return 0;
  853. }
  854. /*===================================================================
  855. CSession::CheckForTombstone
  856. Tombstone stub for ISessionObject methods. If the object is
  857. tombstone, does ExceptionId and fails.
  858. Parameters:
  859. Returns:
  860. HRESULT E_FAIL if Tombstone
  861. S_OK if not
  862. ===================================================================*/
  863. HRESULT CSession::CheckForTombstone()
  864. {
  865. if (!m_fTombstone)
  866. return S_OK;
  867. ExceptionId
  868. (
  869. IID_ISessionObject,
  870. IDE_SESSION,
  871. IDE_INTRINSIC_OUT_OF_SCOPE
  872. );
  873. return E_FAIL;
  874. }
  875. /*===================================================================
  876. CSession::get_SessionID
  877. ISessionObject implementation.
  878. Return the session ID to the caller
  879. Parameters:
  880. BSTR *pbstrRet [out] session id value
  881. Returns:
  882. HRESULT
  883. ===================================================================*/
  884. STDMETHODIMP CSession::get_SessionID
  885. (
  886. BSTR *pbstrRet
  887. )
  888. {
  889. if (FAILED(CheckForTombstone()))
  890. return E_FAIL;
  891. HRESULT hr = S_OK;
  892. wchar_t wszId[15];
  893. _ultow(m_dwExternId, wszId, 10);
  894. *pbstrRet = SysAllocString(wszId);
  895. if (*pbstrRet == NULL)
  896. {
  897. ExceptionId
  898. (
  899. IID_ISessionObject,
  900. IDE_SESSION_ID,
  901. IDE_SESSION_MAP_FAILED
  902. );
  903. hr = E_FAIL;
  904. }
  905. m_fStateAcquired = TRUE;
  906. return hr;
  907. }
  908. /*===================================================================
  909. CSession::get_Timeout
  910. ISessionObject implementation.
  911. Return the default or user set timeout interval (in minutes)
  912. Parameters:
  913. long *plVar [out] timeout value (in minutes)
  914. Returns:
  915. HRESULT
  916. ===================================================================*/
  917. STDMETHODIMP CSession::get_Timeout
  918. (
  919. long *plVar
  920. )
  921. {
  922. if (FAILED(CheckForTombstone()))
  923. return E_FAIL;
  924. *plVar = m_nTimeout;
  925. return S_OK;
  926. }
  927. /*===================================================================
  928. CSession::put_Timeout
  929. ISessionObject implementation.
  930. Allows the user to set the timeout interval (in minutes)
  931. Parameters:
  932. long lVar timeout value (in minutes)
  933. Returns:
  934. HRESULT
  935. ===================================================================*/
  936. STDMETHODIMP CSession::put_Timeout
  937. (
  938. long lVar
  939. )
  940. {
  941. if (FAILED(CheckForTombstone()))
  942. return E_FAIL;
  943. if (lVar < SESSION_TIMEOUT_MIN || lVar > SESSION_TIMEOUT_MAX)
  944. {
  945. ExceptionId
  946. (
  947. IID_ISessionObject,
  948. IDE_SESSION_ID,
  949. IDE_SESSION_INVALID_TIMEOUT
  950. );
  951. return E_FAIL;
  952. }
  953. m_fStateAcquired = TRUE;
  954. m_fCustomTimeout = TRUE;
  955. m_nTimeout = lVar;
  956. return S_OK;
  957. }
  958. /*===================================================================
  959. CSession::get_CodePage
  960. ISessionObject implementation.
  961. Returns the current code page value for the request
  962. Parameters:
  963. long *plVar [out] code page value
  964. Returns:
  965. HRESULT S_OK on success
  966. ===================================================================*/
  967. STDMETHODIMP CSession::get_CodePage
  968. (
  969. long *plVar
  970. )
  971. {
  972. if (FAILED(CheckForTombstone()))
  973. return E_FAIL;
  974. Assert(m_pHitObj);
  975. *plVar = m_lCodePage;
  976. // If code page is 0, look up default ANSI code page
  977. if (*plVar == 0)
  978. {
  979. *plVar = (long) GetACP();
  980. }
  981. return S_OK;
  982. }
  983. /*===================================================================
  984. CSession::put_CodePage
  985. ISessionObject implementation.
  986. Sets the current code page value for the request
  987. Parameters:
  988. long lVar code page to assign to this session
  989. Returns:
  990. HRESULT S_OK on success
  991. ===================================================================*/
  992. STDMETHODIMP CSession::put_CodePage
  993. (
  994. long lVar
  995. )
  996. {
  997. if (FAILED(CheckForTombstone()))
  998. return E_FAIL;
  999. // set code page member variable
  1000. Assert(m_pHitObj);
  1001. HRESULT hr = m_pHitObj->SetCodePage(lVar);
  1002. if (FAILED(hr))
  1003. {
  1004. ExceptionId
  1005. (
  1006. IID_ISessionObject,
  1007. IDE_SESSION_ID,
  1008. IDE_SESSION_INVALID_CODEPAGE
  1009. );
  1010. return E_FAIL;
  1011. }
  1012. m_fCodePageSet = TRUE;
  1013. m_lCodePage = lVar;
  1014. // we need to preserve session since the user has set
  1015. // its code page member variable
  1016. m_fStateAcquired = TRUE;
  1017. return S_OK;
  1018. }
  1019. /*===================================================================
  1020. CSession::get_LCID
  1021. ISessionObject implementation.
  1022. Returns the current lcid value for the request
  1023. Parameters:
  1024. long *plVar [out] code page value
  1025. Returns:
  1026. HRESULT S_OK on success
  1027. ===================================================================*/
  1028. STDMETHODIMP CSession::get_LCID
  1029. (
  1030. long *plVar
  1031. )
  1032. {
  1033. if (FAILED(CheckForTombstone()))
  1034. return E_FAIL;
  1035. Assert(m_pHitObj);
  1036. *plVar = m_lcid;
  1037. if (*plVar == LOCALE_SYSTEM_DEFAULT) {
  1038. *plVar = GetSystemDefaultLCID();
  1039. }
  1040. return S_OK;
  1041. }
  1042. /*===================================================================
  1043. CSession::put_LCID
  1044. ISessionObject implementation.
  1045. Sets the current LCID value for the request
  1046. Parameters:
  1047. long lVar LCID to assign to this session
  1048. Returns:
  1049. HRESULT S_OK on success
  1050. ===================================================================*/
  1051. STDMETHODIMP CSession::put_LCID
  1052. (
  1053. long lVar
  1054. )
  1055. {
  1056. if (FAILED(CheckForTombstone()))
  1057. return E_FAIL;
  1058. // set code page member variable
  1059. Assert(m_pHitObj);
  1060. HRESULT hr = m_pHitObj->SetLCID(lVar);
  1061. if (FAILED(hr))
  1062. {
  1063. ExceptionId
  1064. (
  1065. IID_ISessionObject,
  1066. IDE_SESSION_ID,
  1067. IDE_TEMPLATE_BAD_LCID
  1068. );
  1069. return E_FAIL;
  1070. }
  1071. m_fLCIDSet = TRUE;
  1072. m_lcid = lVar;
  1073. // we need to preserve session since the user has set
  1074. // its lcid member variable
  1075. m_fStateAcquired = TRUE;
  1076. return S_OK;
  1077. }
  1078. /*===================================================================
  1079. CSession::get_Value
  1080. ISessionObject implementation.
  1081. Will allow the user to retreive a session state variable,
  1082. the variable will come as a named pair, bstr is the name and
  1083. var is the value or object to be returned for that name
  1084. Parameters:
  1085. BSTR bstrName Name of the variable to get
  1086. VARIANT *pVar Value/object to get for the variable
  1087. Returns:
  1088. HRESULT S_OK on success
  1089. ===================================================================*/
  1090. STDMETHODIMP CSession::get_Value
  1091. (
  1092. BSTR bstrName,
  1093. VARIANT *pVar
  1094. )
  1095. {
  1096. if (FAILED(CheckForTombstone()))
  1097. return E_FAIL;
  1098. if (bstrName == NULL)
  1099. {
  1100. ExceptionId(IID_ISessionObject, IDE_SESSION, IDE_EXPECTING_STR);
  1101. return E_FAIL;
  1102. }
  1103. VariantInit(pVar); // default variant empty
  1104. WCHAR *pwszName;
  1105. STACK_BUFFER(rgbName, 42);
  1106. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1107. if (pwszName == NULL)
  1108. return S_OK; // no name - no value - no error
  1109. //_wcsupr(pwszName);
  1110. CComponentObject *pObj = NULL;
  1111. HRESULT hr = S_OK;
  1112. Assert(m_pHitObj);
  1113. m_pHitObj->AssertValid();
  1114. hr = m_pHitObj->GetPropertyComponent(csSession, pwszName, &pObj);
  1115. if (SUCCEEDED(hr) && pObj)
  1116. hr = pObj->GetVariant(pVar);
  1117. return S_OK;
  1118. }
  1119. /*===================================================================
  1120. CSession::putref_Value
  1121. ISessionObject implementation.
  1122. Will allow the user to assign a session state variable to be saved
  1123. the variable will come as a named pair, bstr is the name and
  1124. var is the value or object to be stored for that name
  1125. Parameters:
  1126. BSTR bstrName Name of the variable to set
  1127. VARIANT Var Value/object to set for the variable
  1128. Returns:
  1129. HRESULT S_OK on success
  1130. ===================================================================*/
  1131. STDMETHODIMP CSession::putref_Value
  1132. (
  1133. BSTR bstrName,
  1134. VARIANT Var
  1135. )
  1136. {
  1137. if (FAILED(CheckForTombstone()))
  1138. return E_FAIL;
  1139. if (FIsIntrinsic(&Var))
  1140. {
  1141. ExceptionId(IID_ISessionObject, IDE_SESSION,
  1142. IDE_SESSION_CANT_STORE_INTRINSIC);
  1143. return E_FAIL;
  1144. }
  1145. if (bstrName == NULL)
  1146. {
  1147. ExceptionId(IID_ISessionObject, IDE_SESSION, IDE_EXPECTING_STR);
  1148. return E_FAIL;
  1149. }
  1150. HRESULT hr;
  1151. Assert(m_pHitObj);
  1152. m_pHitObj->AssertValid();
  1153. WCHAR *pwszName;
  1154. STACK_BUFFER(rgbName, 42);
  1155. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1156. if (pwszName == NULL)
  1157. {
  1158. ExceptionId
  1159. (
  1160. IID_ISessionObject,
  1161. IDE_SESSION,
  1162. IDE_EXPECTING_STR
  1163. );
  1164. return E_FAIL;
  1165. }
  1166. //_wcsupr(pwszName);
  1167. hr = m_pHitObj->SetPropertyComponent(csSession, pwszName, &Var);
  1168. return hr;
  1169. }
  1170. /*===================================================================
  1171. CSession::put_Value
  1172. ISessionObject implementation.
  1173. Implement property put by dereferencing variants before
  1174. calling putref.
  1175. Parameters:
  1176. BSTR bstrName Name of the variable to set
  1177. VARIANT Var Value/object to set for the variable
  1178. Returns:
  1179. HRESULT S_OK on success
  1180. ===================================================================*/
  1181. STDMETHODIMP CSession::put_Value
  1182. (
  1183. BSTR bstrName,
  1184. VARIANT Var
  1185. )
  1186. {
  1187. if (FAILED(CheckForTombstone()))
  1188. return E_FAIL;
  1189. if (bstrName == NULL)
  1190. {
  1191. ExceptionId(IID_ISessionObject, IDE_SESSION, IDE_EXPECTING_STR);
  1192. return E_FAIL;
  1193. }
  1194. HRESULT hr;
  1195. VARIANT varResolved;
  1196. hr = VariantResolveDispatch
  1197. (
  1198. &varResolved,
  1199. &Var,
  1200. IID_ISessionObject,
  1201. IDE_SESSION
  1202. );
  1203. if (FAILED(hr))
  1204. return hr; // exception already raised
  1205. Assert(m_pHitObj);
  1206. m_pHitObj->AssertValid();
  1207. WCHAR *pwszName;
  1208. STACK_BUFFER(rgbName, 42);
  1209. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1210. if (pwszName == NULL)
  1211. {
  1212. ExceptionId
  1213. (
  1214. IID_ISessionObject,
  1215. IDE_SESSION,
  1216. IDE_EXPECTING_STR
  1217. );
  1218. VariantClear( &varResolved );
  1219. return E_FAIL;
  1220. }
  1221. //_wcsupr(pwszName);
  1222. hr = m_pHitObj->SetPropertyComponent
  1223. (
  1224. csSession,
  1225. pwszName,
  1226. &varResolved
  1227. );
  1228. VariantClear( &varResolved );
  1229. return hr;
  1230. }
  1231. /*===================================================================
  1232. CSession::Abandon
  1233. ISessionObject implementation.
  1234. Abandon reassignes session id to avoid hitting this session
  1235. with incoming requests. Abandoned sessions get deleted ASAP.
  1236. Parameters:
  1237. None
  1238. Returns:
  1239. HRESULT S_OK on success
  1240. ===================================================================*/
  1241. STDMETHODIMP CSession::Abandon()
  1242. {
  1243. if (FAILED(CheckForTombstone()))
  1244. return E_FAIL;
  1245. m_fAbandoned = TRUE;
  1246. // The new session logic allows only one session id per
  1247. // client need to disassociate session from client
  1248. // (good idea when abandoning anyway)
  1249. Assert(m_pHitObj);
  1250. // If execution Session_OnEnd (not a browser request), do nothing
  1251. if (!m_pHitObj->FIsBrowserRequest())
  1252. return S_OK;
  1253. return m_pHitObj->ReassignAbandonedSession();
  1254. }
  1255. /*===================================================================
  1256. CSession::get_StaticObjects
  1257. Return the session static objects dictionary
  1258. ===================================================================*/
  1259. STDMETHODIMP CSession::get_StaticObjects
  1260. (
  1261. IVariantDictionary **ppDictReturn
  1262. )
  1263. {
  1264. if (FAILED(CheckForTombstone()))
  1265. return E_FAIL;
  1266. if (!m_pTaggedObjects)
  1267. {
  1268. m_pTaggedObjects = new CSessionVariants;
  1269. if (!m_pTaggedObjects)
  1270. return E_OUTOFMEMORY;
  1271. HRESULT hr = m_pTaggedObjects->Init(this, ctTagged);
  1272. if (FAILED(hr))
  1273. {
  1274. m_pTaggedObjects->UnInit();
  1275. m_pTaggedObjects->Release();
  1276. m_pTaggedObjects = NULL;
  1277. }
  1278. }
  1279. Assert(m_pTaggedObjects);
  1280. return m_pTaggedObjects->QueryInterface(IID_IVariantDictionary, reinterpret_cast<void **>(ppDictReturn));
  1281. }
  1282. /*===================================================================
  1283. CSession::get_Contents
  1284. Return the session contents dictionary
  1285. ===================================================================*/
  1286. STDMETHODIMP CSession::get_Contents
  1287. (
  1288. IVariantDictionary **ppDictReturn
  1289. )
  1290. {
  1291. if (FAILED(CheckForTombstone()))
  1292. return E_FAIL;
  1293. if (!m_pProperties)
  1294. {
  1295. m_pProperties = new CSessionVariants;
  1296. if (!m_pProperties)
  1297. return E_OUTOFMEMORY;
  1298. HRESULT hr = m_pProperties->Init(this, ctProperty);
  1299. if (FAILED(hr))
  1300. {
  1301. m_pProperties->UnInit();
  1302. m_pProperties->Release();
  1303. m_pProperties = NULL;
  1304. }
  1305. }
  1306. Assert(m_pProperties);
  1307. return m_pProperties->QueryInterface(IID_IVariantDictionary, reinterpret_cast<void **>(ppDictReturn));
  1308. }
  1309. #ifdef DBG
  1310. /*===================================================================
  1311. CSession::AssertValid
  1312. Test to make sure that the CSession object is currently
  1313. correctly formed and assert if it is not.
  1314. Returns:
  1315. None
  1316. Side effects:
  1317. None.
  1318. ===================================================================*/
  1319. VOID CSession::AssertValid() const
  1320. {
  1321. Assert(m_fInited);
  1322. if (!m_fTombstone)
  1323. Assert(m_pAppln);
  1324. }
  1325. #endif // DBG
  1326. /*===================================================================
  1327. C S e s s i o n M g r
  1328. ===================================================================*/
  1329. /*===================================================================
  1330. CSessionMgr::CSessionMgr
  1331. CSessionMgr constructor.
  1332. Parameters:
  1333. NONE
  1334. Returns:
  1335. ===================================================================*/
  1336. CSessionMgr::CSessionMgr()
  1337. :
  1338. m_fInited(FALSE),
  1339. m_pAppln(NULL),
  1340. m_cSessionCleanupRequests(0),
  1341. m_cTimeoutBuckets(0),
  1342. m_rgolTOBuckets(NULL),
  1343. m_idSessionKiller(0),
  1344. m_dwmCurrentTime(0),
  1345. m_dwtNextSessionKillerTime(0)
  1346. {
  1347. }
  1348. /*===================================================================
  1349. CSessionMgr::~CSessionMgr
  1350. CSessionMgr destructor.
  1351. Parameters:
  1352. NONE
  1353. Returns:
  1354. ===================================================================*/
  1355. CSessionMgr::~CSessionMgr()
  1356. {
  1357. UnInit();
  1358. }
  1359. /*===================================================================
  1360. HRESULT CSessionMgr::Init
  1361. Initializes the Session Manager.
  1362. Initializes hash tables.
  1363. Schedules session killer.
  1364. Parameters:
  1365. pAppln Application
  1366. Returns:
  1367. HRESULT
  1368. ===================================================================*/
  1369. HRESULT CSessionMgr::Init
  1370. (
  1371. CAppln *pAppln
  1372. )
  1373. {
  1374. Assert(!m_fInited);
  1375. HRESULT hr;
  1376. m_pAppln = pAppln;
  1377. // Master hash table
  1378. hr = m_htidMaster.Init
  1379. (
  1380. SESSION_MASTERHASH_SIZE1_MAX,
  1381. SESSION_MASTERHASH_SIZE2_MAX,
  1382. SESSION_MASTERHASH_SIZE3_MAX
  1383. );
  1384. if (FAILED(hr))
  1385. return hr;
  1386. // Number of timeout buckets = session timeout in minutes + 1
  1387. m_cTimeoutBuckets =
  1388. m_pAppln->QueryAppConfig()->dwSessionTimeout() + 1;
  1389. if (m_cTimeoutBuckets < SESSION_TIMEOUTBUCKETS_MIN)
  1390. m_cTimeoutBuckets = SESSION_TIMEOUTBUCKETS_MIN;
  1391. else if (m_cTimeoutBuckets > SESSION_TIMEOUTBUCKETS_MAX)
  1392. m_cTimeoutBuckets = SESSION_TIMEOUTBUCKETS_MAX;
  1393. // Timeout buckets hash tables array
  1394. m_rgolTOBuckets = new CObjectListWithLock[m_cTimeoutBuckets];
  1395. if (!m_rgolTOBuckets)
  1396. return E_OUTOFMEMORY;
  1397. // Each timeout bucket hash table
  1398. for (DWORD i = 0; i < m_cTimeoutBuckets; i++)
  1399. {
  1400. hr = m_rgolTOBuckets[i].Init
  1401. (
  1402. OBJECT_LIST_ELEM_FIELD_OFFSET(CSession, m_TOBucketElem)
  1403. );
  1404. if (FAILED(hr))
  1405. return hr;
  1406. }
  1407. // Schedule session killer
  1408. hr = ScheduleSessionKiller();
  1409. if (FAILED(hr))
  1410. return hr;
  1411. // Start counting time
  1412. m_dwmCurrentTime = 0;
  1413. // Remember the time of the next session killer
  1414. m_dwtNextSessionKillerTime = ::GetTickCount() + MSEC_ONE_MINUTE;
  1415. m_fInited = TRUE;
  1416. return S_OK;
  1417. }
  1418. /*===================================================================
  1419. HRESULT CSessionMgr::UnInit
  1420. UnInitializes the Session Manager.
  1421. Parameters:
  1422. Returns:
  1423. S_OK
  1424. ===================================================================*/
  1425. HRESULT CSessionMgr::UnInit( void )
  1426. {
  1427. // Un-schedule session killer
  1428. if (m_idSessionKiller)
  1429. UnScheduleSessionKiller();
  1430. // Timeout buckets
  1431. if (m_rgolTOBuckets)
  1432. {
  1433. for (DWORD i = 0; i < m_cTimeoutBuckets; i++)
  1434. m_rgolTOBuckets[i].UnInit();
  1435. delete [] m_rgolTOBuckets;
  1436. m_rgolTOBuckets = NULL;
  1437. }
  1438. m_cTimeoutBuckets = 0;
  1439. // Master hash
  1440. m_htidMaster.UnInit();
  1441. m_fInited = FALSE;
  1442. return S_OK;
  1443. }
  1444. /*===================================================================
  1445. CSessionMgr::ScheduleSessionKiller
  1446. Sets up the session killer workitem for ATQ scheduler
  1447. Parameters:
  1448. Returns:
  1449. HRESULT
  1450. ===================================================================*/
  1451. HRESULT CSessionMgr::ScheduleSessionKiller()
  1452. {
  1453. Assert(!m_idSessionKiller);
  1454. m_idSessionKiller = ScheduleWorkItem
  1455. (
  1456. CSessionMgr::SessionKillerSchedulerCallback, // callback
  1457. this, // context
  1458. MSEC_ONE_MINUTE, // timeout
  1459. TRUE // periodic
  1460. );
  1461. return m_idSessionKiller ? S_OK : E_FAIL;
  1462. }
  1463. /*===================================================================
  1464. CSessionMgr::UnScheduleSessionKiller
  1465. Removes the session killer workitem for ATQ scheduler
  1466. Parameters:
  1467. Returns:
  1468. S_OK
  1469. ===================================================================*/
  1470. HRESULT CSessionMgr::UnScheduleSessionKiller()
  1471. {
  1472. if (m_idSessionKiller)
  1473. {
  1474. RemoveWorkItem(m_idSessionKiller);
  1475. m_idSessionKiller = 0;
  1476. }
  1477. return S_OK;
  1478. }
  1479. /*===================================================================
  1480. CSessionMgr::GenerateIdAndCookie
  1481. Generate new ID and cookie to be used create new session
  1482. or reassign the session ID for an existing session.
  1483. Parameters:
  1484. pId [out] ID
  1485. pszNewCookie [out] Cookie (buf must be long enough)
  1486. Returns:
  1487. S_OK
  1488. ===================================================================*/
  1489. HRESULT CSessionMgr::GenerateIdAndCookie
  1490. (
  1491. CSessionId *pId,
  1492. char *pszNewCookie
  1493. )
  1494. {
  1495. pId->m_dwId = g_SessionIdGenerator.NewId();
  1496. GenerateRandomDwords(&pId->m_dwR1, 2);
  1497. EncodeSessionIdCookie
  1498. (
  1499. pId->m_dwId,
  1500. pId->m_dwR1,
  1501. pId->m_dwR2,
  1502. pszNewCookie
  1503. );
  1504. return S_OK;
  1505. }
  1506. /*===================================================================
  1507. CSessionMgr::NewSession
  1508. Creates and Inits a new CSession object
  1509. Parameters:
  1510. Id session id
  1511. ppSession [out] session created
  1512. Returns:
  1513. HRESULT
  1514. ===================================================================*/
  1515. HRESULT CSessionMgr::NewSession
  1516. (
  1517. const CSessionId &Id,
  1518. CSession **ppSession
  1519. )
  1520. {
  1521. Assert(m_fInited);
  1522. HRESULT hr = S_OK;
  1523. CSession *pSession = new CSession;
  1524. if (!pSession)
  1525. hr = E_OUTOFMEMORY;
  1526. if (SUCCEEDED(hr))
  1527. hr = pSession->Init(m_pAppln, Id);
  1528. if (SUCCEEDED(hr))
  1529. {
  1530. Assert(pSession);
  1531. *ppSession = pSession;
  1532. }
  1533. else
  1534. {
  1535. // failed - do cleanup
  1536. if (pSession)
  1537. {
  1538. pSession->UnInit();
  1539. pSession->Release();
  1540. }
  1541. *ppSession = NULL;
  1542. }
  1543. return hr;
  1544. }
  1545. /*===================================================================
  1546. CSessionMgr::ChangeSessionId
  1547. Reassigns different session Id to a session.
  1548. Updates the master hash.
  1549. This method is called when abandoning a session
  1550. to disassociate it from the client.
  1551. Parameters:
  1552. pSession session to change id on
  1553. Id new session id to assign
  1554. Returns:
  1555. S_OK on success
  1556. E_FAIL on failure
  1557. ===================================================================*/
  1558. HRESULT CSessionMgr::ChangeSessionId
  1559. (
  1560. CSession *pSession,
  1561. const CSessionId &Id
  1562. )
  1563. {
  1564. HRESULT hr;
  1565. // During request processing session's not supposed to be
  1566. // in any timeout bucket
  1567. Assert(!pSession->m_fInTOBucket);
  1568. LockMaster();
  1569. // Remove from master hash by Id
  1570. hr = RemoveFromMasterHash(pSession);
  1571. if (SUCCEEDED(hr))
  1572. {
  1573. // Assign new id
  1574. pSession->AssignNewId(Id);
  1575. // Reinsert into master hash by id
  1576. hr = AddToMasterHash(pSession);
  1577. }
  1578. UnLockMaster();
  1579. return hr;
  1580. }
  1581. /*===================================================================
  1582. CSessionMgr::FindInMasterHash
  1583. Finds Session in master hash session id.
  1584. Doesn't Lock.
  1585. Parameters:
  1586. Id session id to find
  1587. **ppSession [out] session found
  1588. Returns:
  1589. S_OK good session found
  1590. S_FALSE session not found or bad session found
  1591. ===================================================================*/
  1592. HRESULT CSessionMgr::FindInMasterHash
  1593. (
  1594. const CSessionId &Id,
  1595. CSession **ppSession
  1596. )
  1597. {
  1598. Assert(m_fInited);
  1599. // Find in the hash table
  1600. HRESULT hr = m_htidMaster.FindObject(Id.m_dwId, (void **)ppSession);
  1601. if (hr != S_OK)
  1602. {
  1603. // Not found
  1604. *ppSession = NULL;
  1605. return hr;
  1606. }
  1607. // Session found, check if valid
  1608. if ((*ppSession)->m_fAbandoned ||
  1609. (*ppSession)->m_fTombstone ||
  1610. !(*ppSession)->FPassesIdSecurityCheck(Id.m_dwR1, Id.m_dwR2))
  1611. {
  1612. // Bad session
  1613. hr = S_FALSE;
  1614. }
  1615. return hr;
  1616. }
  1617. /*===================================================================
  1618. CSessionMgr::AddSessionToTOBucket
  1619. Adds session to the correct timeout bucket.
  1620. Locks the timeout bucket.
  1621. Parameters:
  1622. pSession - session to add
  1623. Returns:
  1624. HRESULT
  1625. ===================================================================*/
  1626. HRESULT CSessionMgr::AddSessionToTOBucket
  1627. (
  1628. CSession *pSession
  1629. )
  1630. {
  1631. HRESULT hr;
  1632. // Should not be already in a timeout bucket
  1633. Assert(!pSession->m_fInTOBucket);
  1634. DWORD iBucket = GetSessionTOBucket(pSession);
  1635. LockTOBucket(iBucket);
  1636. hr = m_rgolTOBuckets[iBucket].AddObject(pSession);
  1637. if (SUCCEEDED(hr))
  1638. pSession->m_fInTOBucket = TRUE;
  1639. UnLockTOBucket(iBucket);
  1640. return hr;
  1641. }
  1642. /*===================================================================
  1643. CSessionMgr::RemoveSessionToTOBucket
  1644. Removes from its timeout bucket if any.
  1645. Locks the timeout bucket.
  1646. Parameters:
  1647. pSession - session to remove
  1648. fLock - lock bucket? (not needed during shutdown)
  1649. Returns:
  1650. HRESULT
  1651. ===================================================================*/
  1652. HRESULT CSessionMgr::RemoveSessionFromTOBucket
  1653. (
  1654. CSession *pSession,
  1655. BOOL fLock
  1656. )
  1657. {
  1658. HRESULT hr;
  1659. Assert(m_fInited);
  1660. Assert(pSession->m_fInited);
  1661. if (!pSession->m_fInTOBucket) // not there - no error
  1662. return S_OK;
  1663. DWORD iBucket = GetSessionTOBucket(pSession);
  1664. if (fLock)
  1665. LockTOBucket(iBucket);
  1666. if (pSession->m_fInTOBucket) // recheck after locking
  1667. hr = m_rgolTOBuckets[iBucket].RemoveObject(pSession);
  1668. else
  1669. hr = S_OK;
  1670. if (SUCCEEDED(hr))
  1671. pSession->m_fInTOBucket = FALSE;
  1672. if (fLock)
  1673. UnLockTOBucket(iBucket);
  1674. return hr;
  1675. }
  1676. /*===================================================================
  1677. CSessionMgr::DeleteSession
  1678. Delete now or post for deletion.
  1679. Should be called after the session is gone from the hash table
  1680. Parameters:
  1681. CSession *pSession - session to release
  1682. BOOL fInSessionActivity - TRUE when deleting HitObj's session
  1683. at the end of request (no Async
  1684. calls needed)
  1685. Returns:
  1686. HRESULT (S_OK)
  1687. ===================================================================*/
  1688. HRESULT CSessionMgr::DeleteSession
  1689. (
  1690. CSession *pSession,
  1691. BOOL fInSessionActivity
  1692. )
  1693. {
  1694. Assert(pSession);
  1695. pSession->AssertValid();
  1696. // Take care of DELETE NOW case
  1697. BOOL fDeleteNow = pSession->FCanDeleteWithoutExec();
  1698. // If called not from the session's activity and session
  1699. // has objects then need to switch to the right activity
  1700. // to remove the session level objects
  1701. if (!fInSessionActivity && pSession->FHasObjects())
  1702. fDeleteNow = FALSE;
  1703. if (fDeleteNow)
  1704. {
  1705. pSession->UnInit();
  1706. pSession->Release();
  1707. return S_OK;
  1708. }
  1709. // THE ASYNC DELETE LOGIC
  1710. HRESULT hr = S_OK;
  1711. // Make sure session object exists after AsyncCall
  1712. pSession->AddRef();
  1713. // Create new HitObj and init it for session delete
  1714. CHitObj *pHitObj = new CHitObj;
  1715. if (pHitObj)
  1716. {
  1717. pHitObj->SessionCleanupInit(pSession);
  1718. if (fInSessionActivity)
  1719. {
  1720. // Already inside the correct activity no need to
  1721. // push the call through Viper
  1722. BOOL fRequestReposted = FALSE;
  1723. pHitObj->ViperAsyncCallback(&fRequestReposted);
  1724. Assert(!fRequestReposted); // this better not happen
  1725. delete pHitObj;
  1726. }
  1727. else
  1728. {
  1729. // Ask Viper to post the request
  1730. hr = pHitObj->PostViperAsyncCall();
  1731. if (FAILED(hr))
  1732. delete pHitObj;
  1733. }
  1734. }
  1735. else
  1736. {
  1737. hr = E_OUTOFMEMORY;
  1738. }
  1739. if (FAILED(hr))
  1740. {
  1741. // Out of memery or Viper failed to post a request
  1742. // Force the issue inside TRY CATCH
  1743. // (not always safe to delete in the wrong thread)
  1744. TRY
  1745. hr = pSession->UnInit();
  1746. CATCH(nExcept)
  1747. pSession->m_fTombstone = TRUE;
  1748. CoDisconnectObject(static_cast<ISessionObject *>(pSession), 0);
  1749. hr = E_UNEXPECTED;
  1750. END_TRY
  1751. pSession->Release();
  1752. }
  1753. pSession->Release(); // Undo AddRef()
  1754. return S_OK;
  1755. }
  1756. /*===================================================================
  1757. CSessionMgr::DeleteExpiredSessions
  1758. Removes expired Sessions from a given timeout bucket
  1759. Parameters:
  1760. iBucket timeout bucket #
  1761. Returns:
  1762. HRESULT (S_OK)
  1763. ===================================================================*/
  1764. HRESULT CSessionMgr::DeleteExpiredSessions
  1765. (
  1766. DWORD iBucket
  1767. )
  1768. {
  1769. LockTOBucket(iBucket);
  1770. void *pvSession = m_rgolTOBuckets[iBucket].PFirstObject();
  1771. while (pvSession && !IsShutDownInProgress())
  1772. {
  1773. CSession *pSession = reinterpret_cast<CSession *>(pvSession);
  1774. pvSession = m_rgolTOBuckets[iBucket].PNextObject(pvSession);
  1775. if (pSession->GetRequestsCount() == 0)
  1776. {
  1777. BOOL fTimedOut = pSession->GetTimeoutTime() <= GetCurrentTime();
  1778. BOOL fRemovedFromMasterHash = FALSE;
  1779. if (fTimedOut || pSession->FShouldBeDeletedNow(FALSE))
  1780. {
  1781. LockMaster();
  1782. if (pSession->GetRequestsCount() == 0) // recheck after lock
  1783. {
  1784. RemoveFromMasterHash(pSession);
  1785. fRemovedFromMasterHash = TRUE;
  1786. }
  1787. UnLockMaster();
  1788. }
  1789. if (fRemovedFromMasterHash)
  1790. {
  1791. if (fTimedOut)
  1792. pSession->m_fTimedOut = TRUE;
  1793. // delete from timeout bucket
  1794. m_rgolTOBuckets[iBucket].RemoveObject(pSession);
  1795. pSession->m_fInTOBucket = FALSE;
  1796. // delete session object itself (or schedule for deletion)
  1797. DeleteSession(pSession);
  1798. }
  1799. }
  1800. }
  1801. UnLockTOBucket(iBucket);
  1802. return S_OK;
  1803. }
  1804. /*===================================================================
  1805. CSessionMgr::DeleteAllSessions
  1806. Application shutdown code.
  1807. Parameters:
  1808. fForce flag - force delete?
  1809. Returns:
  1810. HRESULT (S_OK)
  1811. ===================================================================*/
  1812. HRESULT CSessionMgr::DeleteAllSessions
  1813. (
  1814. BOOL fForce
  1815. )
  1816. {
  1817. // Remove session killer so that it wouldn't interfere
  1818. UnScheduleSessionKiller();
  1819. LockMaster();
  1820. HRESULT hr = m_htidMaster.IterateObjects
  1821. (
  1822. DeleteAllSessionsCB,
  1823. this,
  1824. &fForce
  1825. );
  1826. if (fForce)
  1827. m_htidMaster.RemoveAllObjects();
  1828. UnLockMaster();
  1829. return hr;
  1830. }
  1831. /*===================================================================
  1832. CSessionMgr::DeleteAllSessionsCB
  1833. Static iterator callback.
  1834. Removes Session regardless.
  1835. Parameters:
  1836. pvSession session passed as void*
  1837. pvSessionMgr session manager passed as void*
  1838. pvfForce flag if TRUE - force the issue
  1839. Returns:
  1840. IteratorCallbackCode
  1841. ===================================================================*/
  1842. IteratorCallbackCode CSessionMgr::DeleteAllSessionsCB
  1843. (
  1844. void *pvSession,
  1845. void *pvSessionMgr,
  1846. void *pvfForce
  1847. )
  1848. {
  1849. IteratorCallbackCode rc = iccContinue;
  1850. CSession *pSession = reinterpret_cast<CSession *>(pvSession);
  1851. CSessionMgr *pMgr = reinterpret_cast<CSessionMgr *>(pvSessionMgr);
  1852. BOOL fForce = *(reinterpret_cast<BOOL *>(pvfForce));
  1853. // Try for 5 seconds to post delete for each session
  1854. for (int iT = 0; iT < 10; iT++)
  1855. {
  1856. if (pSession->GetRequestsCount() == 0)
  1857. {
  1858. if (fForce)
  1859. {
  1860. // When forcing delete and there are too many
  1861. // session cleanup requests quequed
  1862. // wait for the queue to drain
  1863. while (pMgr->GetNumSessionCleanupRequests() >= SUGGESTED_SESSION_CLEANUP_REQUESTS_MAX)
  1864. Sleep(100);
  1865. }
  1866. else // if (!fForce)
  1867. {
  1868. // When not forcing delete (on application restart)
  1869. // don't queue too many sessions at one time
  1870. if (pMgr->GetNumSessionCleanupRequests() < SUGGESTED_SESSION_CLEANUP_REQUESTS_MAX)
  1871. rc = iccRemoveAndContinue;
  1872. else
  1873. rc = iccRemoveAndStop;
  1874. }
  1875. if (pSession->FInTOBucket())
  1876. pMgr->RemoveSessionFromTOBucket(pSession, !fForce);
  1877. pMgr->DeleteSession(pSession);
  1878. break;
  1879. }
  1880. if (!fForce)
  1881. break;
  1882. Sleep(500);
  1883. }
  1884. return rc;
  1885. }
  1886. /*===================================================================
  1887. CSessionMgr::SessionKillerSchedulerCallback
  1888. Static method implements ATQ scheduler callback functions.
  1889. Replaces session killer thread
  1890. Parameters:
  1891. void *pv context pointer (points to appl)
  1892. Returns:
  1893. Side effects:
  1894. None.
  1895. ===================================================================*/
  1896. void WINAPI CSessionMgr::SessionKillerSchedulerCallback
  1897. (
  1898. void *pv
  1899. )
  1900. {
  1901. if (IsShutDownInProgress())
  1902. return;
  1903. Assert(pv);
  1904. CSessionMgr *pMgr = reinterpret_cast<CSessionMgr *>(pv);
  1905. // Advance session killer time by 1 [minute]
  1906. pMgr->m_dwmCurrentTime++;
  1907. // Choose the bucket
  1908. DWORD iBucket = pMgr->m_dwmCurrentTime % pMgr->m_cTimeoutBuckets;
  1909. // Kill the sessions
  1910. pMgr->DeleteExpiredSessions(iBucket);
  1911. // Adjust the timeout to stay on the minute boundary
  1912. pMgr->m_dwtNextSessionKillerTime += MSEC_ONE_MINUTE;
  1913. // Calculate wait till next callback wakes up
  1914. DWORD dwtCur = ::GetTickCount();
  1915. DWORD dwtWait = 5000; // 5 sec if we are already late
  1916. // if (dwtCur < pMgr->m_dwtNextSessionKillerTime)
  1917. // {
  1918. dwtWait = pMgr->m_dwtNextSessionKillerTime - dwtCur;
  1919. if (dwtWait > MSEC_ONE_MINUTE)
  1920. dwtWait = MSEC_ONE_MINUTE; // in case of wrap-around
  1921. // }
  1922. ScheduleAdjustTime(pMgr->m_idSessionKiller, dwtWait);
  1923. }
  1924. #ifdef DBG
  1925. /*===================================================================
  1926. CSessionMgr::AssertValid
  1927. Test to make sure that this is currently correctly formed
  1928. and assert if it is not.
  1929. Returns:
  1930. ===================================================================*/
  1931. void CSessionMgr::AssertValid() const
  1932. {
  1933. Assert(m_fInited);
  1934. }
  1935. #endif