Leaked source code of windows server 2003
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.

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