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.

1997 lines
51 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: Viper Integration Objects
  6. File: viperint.cpp
  7. Owner: DmitryR
  8. This file contains the implementation of viper integration classes
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "Context.h"
  13. #include "package.h"
  14. #include "memchk.h"
  15. #include "denali.h"
  16. #include "perfdata.h"
  17. #include "etwtrace.hxx"
  18. extern HDESK ghDesktop;
  19. //
  20. // COM holds the last reference to a CViperAsyncRequest
  21. // we need to track these objects to ensure that we don't
  22. // exit before the activity threads have released them.
  23. //
  24. volatile LONG g_nViperRequests = 0;
  25. LONG g_nThreadsExecuting = 0;
  26. CViperReqManager g_ViperReqMgr;
  27. DWORD g_ReqDisconnected = 0;
  28. BOOL g_fFirstMTAHit = TRUE;
  29. BOOL g_fFirstSTAHit = TRUE;
  30. extern CRITICAL_SECTION g_csFirstMTAHitLock;
  31. extern CRITICAL_SECTION g_csFirstSTAHitLock;
  32. #if REFTRACE_VIPER_REQUESTS
  33. PTRACE_LOG CViperAsyncRequest::gm_pTraceLog=NULL;
  34. #endif
  35. /*===================================================================
  36. C V i p e r A s y n c R e q u e s t
  37. ===================================================================*/
  38. /*===================================================================
  39. CViperAsyncRequest::CViperAsyncRequest
  40. CViperAsyncRequest constructor
  41. Parameters:
  42. Returns:
  43. ===================================================================*/
  44. CViperAsyncRequest::CViperAsyncRequest()
  45. : m_cRefs(1),
  46. m_pHitObj(NULL),
  47. m_hrOnError(S_OK),
  48. m_pActivity(NULL),
  49. m_fTestingConnection(0),
  50. m_dwRepostAttempts(0),
  51. m_fAsyncCallPosted(0)
  52. {
  53. #if DEBUG_REQ_SCAVENGER
  54. DBGPRINTF((DBG_CONTEXT, "CViperAsyncRequest::CViperAsyncRequest (%p)\n", this));
  55. #endif
  56. #if REFTRACE_VIPER_REQUESTS
  57. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  58. #endif
  59. InterlockedIncrement( (LONG *)&g_nViperRequests );
  60. }
  61. /*===================================================================
  62. CViperAsyncRequest::~CViperAsyncRequest
  63. CViperAsyncRequest destructor
  64. Parameters:
  65. Returns:
  66. ===================================================================*/
  67. CViperAsyncRequest::~CViperAsyncRequest()
  68. {
  69. #if DEBUG_REQ_SCAVENGER
  70. DBGPRINTF((DBG_CONTEXT, "CViperAsyncRequest::~CViperAsyncRequest (%p)\n", this));
  71. #endif
  72. InterlockedDecrement( (LONG *)&g_nViperRequests );
  73. }
  74. /*===================================================================
  75. CViperAsyncRequest::Init
  76. Initialize CViperAsyncRequest with CHitObj object
  77. Parameters:
  78. CHitObj *pHitObj Denali HitObj
  79. Returns:
  80. HRESULT
  81. ===================================================================*/
  82. HRESULT CViperAsyncRequest::Init
  83. (
  84. CHitObj *pHitObj,
  85. IServiceActivity *pActivity
  86. )
  87. {
  88. Assert(m_pHitObj == NULL);
  89. m_pHitObj = pHitObj;
  90. m_pActivity = pActivity;
  91. m_fBrowserRequest = pHitObj->FIsBrowserRequest();
  92. m_dwLastTestTimeStamp = GetTickCount();
  93. // establish the timeout value for this request. It will be a factor
  94. // of the configured QueueConnectionTestTime. In proc, it will be
  95. // this value times 2, and out of proc it will be multiplied by 4.
  96. // NOTE if the QueueConnectionTestTime is zero, we'll use hard
  97. // constants 12 and 6 for oop and inproc, respectively.
  98. DWORD dwQueueConnectionTestTime = pHitObj->PAppln()->QueryAppConfig()->dwQueueConnectionTestTime();
  99. m_dwTimeout = dwQueueConnectionTestTime
  100. ? dwQueueConnectionTestTime * (g_fOOP ? 4 : 2)
  101. : g_fOOP ? 12 : 6;
  102. return S_OK;
  103. }
  104. #ifdef DBG
  105. /*===================================================================
  106. CViperAsyncRequest::AssertValid
  107. Test to make sure that this is currently correctly formed
  108. and assert if it is not.
  109. Returns:
  110. ===================================================================*/
  111. void CViperAsyncRequest::AssertValid() const
  112. {
  113. Assert(m_pHitObj);
  114. Assert(m_cRefs > 0);
  115. }
  116. #endif
  117. /*===================================================================
  118. CViperAsyncRequest::QueryInterface
  119. Standard IUnknown method
  120. Parameters:
  121. REFIID iid
  122. void **ppv
  123. Returns:
  124. HRESULT
  125. ===================================================================*/
  126. STDMETHODIMP CViperAsyncRequest::QueryInterface
  127. (
  128. REFIID iid,
  129. void **ppv
  130. )
  131. {
  132. if (iid == IID_IUnknown || iid == IID_IServiceCall) {
  133. *ppv = this;
  134. AddRef();
  135. return S_OK;
  136. }
  137. else if (iid == IID_IAsyncErrorNotify) {
  138. *ppv = static_cast<IAsyncErrorNotify *>(this);
  139. AddRef();
  140. return S_OK;
  141. }
  142. return E_NOINTERFACE;
  143. }
  144. /*===================================================================
  145. CViperAsyncRequest::AddRef
  146. Standard IUnknown method
  147. Parameters:
  148. Returns:
  149. Ref count
  150. ===================================================================*/
  151. STDMETHODIMP_(ULONG) CViperAsyncRequest::AddRef()
  152. {
  153. LONG refs = InterlockedIncrement(&m_cRefs);
  154. #if REFTRACE_VIPER_REQUESTS
  155. WriteRefTraceLog(gm_pTraceLog, refs, this);
  156. #endif
  157. return refs;
  158. }
  159. /*===================================================================
  160. CViperAsyncRequest::Release
  161. Standard IUnknown method
  162. Parameters:
  163. Returns:
  164. Ref count
  165. ===================================================================*/
  166. STDMETHODIMP_(ULONG) CViperAsyncRequest::Release()
  167. {
  168. LONG refs = InterlockedDecrement(&m_cRefs);
  169. #if REFTRACE_VIPER_REQUESTS
  170. WriteRefTraceLog(gm_pTraceLog, refs, this);
  171. #endif
  172. if (refs != 0)
  173. return refs;
  174. delete this;
  175. return 0;
  176. }
  177. /*===================================================================
  178. CViperAsyncRequest::OnCall
  179. IMTSCall method implementation. This method is called by Viper
  180. from the right thread when it's time to process a request
  181. Parameters:
  182. Returns:
  183. HRESULT
  184. ===================================================================*/
  185. STDMETHODIMP CViperAsyncRequest::OnCall()
  186. {
  187. Assert(m_pHitObj);
  188. CIsapiReqInfo *pIReq;
  189. HCONN ConnId = 0;
  190. InterlockedIncrement(&g_nThreadsExecuting);
  191. // check to see if the request has been removed from the queue
  192. // already. If so, get out of here quick.
  193. if (g_ViperReqMgr.RemoveReqObj(this) == FALSE) {
  194. Release();
  195. InterlockedDecrement(&g_nThreadsExecuting);
  196. return S_OK;
  197. }
  198. pIReq = m_pHitObj->PIReq();
  199. BOOL fRequestReposted = FALSE;
  200. // add an extra addref here to prevent the deletion of the
  201. // hitobj deleting the CIsapiReqInfo for this request.
  202. if (pIReq) {
  203. pIReq->AddRef();
  204. //
  205. // Add an ETW trace event when the request is getting processed.
  206. //
  207. if (ETW_IS_TRACE_ON(ETW_LEVEL_CP) && g_pEtwTracer ) {
  208. ConnId = pIReq->ECB()->ConnID;
  209. g_pEtwTracer->EtwTraceEvent(&AspEventGuid,
  210. EVENT_TRACE_TYPE_START,
  211. &ConnId, sizeof(HCONN),
  212. NULL, 0);
  213. }
  214. }
  215. m_pHitObj->ViperAsyncCallback(&fRequestReposted);
  216. // Make sure there always is DONE_WITH_SESSION
  217. if (m_pHitObj->FIsBrowserRequest() && !fRequestReposted)
  218. {
  219. if (!m_pHitObj->FDoneWithSession())
  220. m_pHitObj->ReportServerError(IDE_UNEXPECTED);
  221. }
  222. if (!fRequestReposted)
  223. delete m_pHitObj; // don't delete if reposted
  224. m_pHitObj = NULL; // set to NULL even if not deleted
  225. Release(); // release this, Viper holds another ref
  226. //
  227. // Add an ETW event when we are done with the request
  228. //
  229. if (pIReq) {
  230. if ( ETW_IS_TRACE_ON(ETW_LEVEL_CP) && g_pEtwTracer) {
  231. g_pEtwTracer->EtwTraceEvent(&AspEventGuid,
  232. ETW_TYPE_END,
  233. &ConnId, sizeof(HCONN),
  234. NULL, 0);
  235. }
  236. pIReq->Release();
  237. }
  238. InterlockedDecrement(&g_nThreadsExecuting);
  239. return S_OK;
  240. }
  241. /*===================================================================
  242. CViperAsyncRequest::OnError
  243. Called by COM+ when it is unable to dispatch the request properly
  244. on the configured thread
  245. Parameters:
  246. Returns:
  247. HRESULT
  248. ===================================================================*/
  249. STDMETHODIMP CViperAsyncRequest::OnError(HRESULT hrViperError)
  250. {
  251. Assert(m_pHitObj);
  252. CIsapiReqInfo *pIReq;
  253. HRESULT hr = S_OK;
  254. // check to see if the request has been removed from the queue
  255. // already. If so, get out of here quick.
  256. if (g_ViperReqMgr.RemoveReqObj(this) == FALSE) {
  257. Release();
  258. return S_OK;
  259. }
  260. pIReq = m_pHitObj->PIReq();
  261. if (pIReq)
  262. pIReq->AddRef();
  263. m_dwRepostAttempts++;
  264. // attempt to repost the request if it hasn't errored out three
  265. // times yet.
  266. if (m_dwRepostAttempts <= 3) {
  267. hr = m_pActivity->AsynchronousCall(this);
  268. Assert(SUCCEEDED(hr));
  269. }
  270. // if it has errored out three times or the repost failed,
  271. // pitch the request
  272. if (FAILED(hr) || (m_dwRepostAttempts > 3)) {
  273. // DONE_WITH_SESSION -- ServerSupportFunction
  274. // does not need bracketing
  275. if (m_pHitObj->FIsBrowserRequest())
  276. m_pHitObj->ReportServerError(IDE_UNEXPECTED);
  277. // We never called to process request, there should
  278. // be no state and it's probably save to delete it
  279. // outside of bracketing
  280. delete m_pHitObj;
  281. m_pHitObj = NULL; // set to NULL even if not deleted
  282. Release(); // release this, Viper holds another ref
  283. }
  284. if (pIReq)
  285. pIReq->Release();
  286. return S_OK;
  287. }
  288. DWORD CViperAsyncRequest::SecsSinceLastTest()
  289. {
  290. DWORD dwt = GetTickCount();
  291. if (dwt >= m_dwLastTestTimeStamp)
  292. return ((dwt - m_dwLastTestTimeStamp)/1000);
  293. else
  294. return (((0xffffffff - m_dwLastTestTimeStamp) + dwt)/1000);
  295. }
  296. /*===================================================================
  297. C V i p e r A c t i v i t y
  298. ===================================================================*/
  299. /*===================================================================
  300. CViperActivity::CViperActivity
  301. CViperActivity constructor
  302. Parameters:
  303. Returns:
  304. ===================================================================*/
  305. CViperActivity::CViperActivity()
  306. : m_pActivity(NULL), m_cBind(0)
  307. {
  308. }
  309. /*===================================================================
  310. CViperActivity::~CViperActivity
  311. CViperActivity destructor
  312. Parameters:
  313. Returns:
  314. ===================================================================*/
  315. CViperActivity::~CViperActivity()
  316. {
  317. UnInit();
  318. }
  319. /*===================================================================
  320. CViperActivity::Init
  321. Create actual Viper activity using MTSCreateActivity()
  322. Parameters:
  323. Returns:
  324. HRESULT
  325. ===================================================================*/
  326. HRESULT CViperActivity::Init(IUnknown *pServicesConfig)
  327. {
  328. Assert(!FInited());
  329. HRESULT hr = S_OK;
  330. hr = CoCreateActivity(pServicesConfig, IID_IServiceActivity, (void **)&m_pActivity);
  331. if (FAILED(hr))
  332. return hr;
  333. m_cBind = 1;
  334. return S_OK;
  335. }
  336. /*===================================================================
  337. CViperActivity::InitClone
  338. Clone Viper activity (AddRef() it)
  339. Parameters:
  340. CViperActivity *pActivity activity to clone from
  341. Returns:
  342. HRESULT
  343. ===================================================================*/
  344. HRESULT CViperActivity::InitClone
  345. (
  346. CViperActivity *pActivity
  347. )
  348. {
  349. Assert(!FInited());
  350. Assert(pActivity);
  351. pActivity->AssertValid();
  352. m_pActivity = pActivity->m_pActivity;
  353. m_pActivity->AddRef();
  354. m_cBind = 1;
  355. return S_OK;
  356. }
  357. /*===================================================================
  358. CViperActivity::UnInit
  359. Release Viper activity
  360. Parameters:
  361. Returns:
  362. HRESULT
  363. ===================================================================*/
  364. HRESULT CViperActivity::UnInit()
  365. {
  366. if (m_pActivity)
  367. {
  368. while (m_cBind > 1) // 1 is for inited flag
  369. {
  370. m_pActivity->UnbindFromThread();
  371. m_cBind--;
  372. }
  373. m_pActivity->Release();
  374. m_pActivity = NULL;
  375. }
  376. m_cBind = 0;
  377. return S_OK;
  378. }
  379. /*===================================================================
  380. CViperActivity::BindToThread
  381. Bind Activity to current thread using IMTSActivity method
  382. Parameters:
  383. Returns:
  384. HRESULT
  385. ===================================================================*/
  386. HRESULT CViperActivity::BindToThread()
  387. {
  388. Assert(FInited());
  389. m_pActivity->BindToCurrentThread();
  390. m_cBind++;
  391. return S_OK;
  392. }
  393. /*===================================================================
  394. CViperActivity::UnBindFromThread
  395. UnBind Activity from using IMTSActivity method
  396. Parameters:
  397. Returns:
  398. HRESULT
  399. ===================================================================*/
  400. HRESULT CViperActivity::UnBindFromThread()
  401. {
  402. Assert(FInited());
  403. Assert(m_cBind > 1);
  404. m_pActivity->UnbindFromThread();
  405. m_cBind--;
  406. return S_OK;
  407. }
  408. /*===================================================================
  409. CViperActivity::PostAsyncRequest
  410. Call HitObj Async.
  411. Creates IMTSCCall object to do it.
  412. Parameters:
  413. CHitObj *pHitObj Denali's HitObj
  414. Returns:
  415. HRESULT
  416. ===================================================================*/
  417. HRESULT CViperActivity::PostAsyncRequest
  418. (
  419. CHitObj *pHitObj
  420. )
  421. {
  422. AssertValid();
  423. HRESULT hr = S_OK;
  424. CViperAsyncRequest *pViperCall = new CViperAsyncRequest;
  425. if (!pViperCall)
  426. hr = E_OUTOFMEMORY;
  427. else
  428. hr = pViperCall->Init(pHitObj, m_pActivity);
  429. // Revert to Self before exiting so that it will be in a consistent (impersonated) state
  430. // when it leaves this function.
  431. RevertToSelf();
  432. // hr here can be either S_OK or E_OUTOFMEMORY both cases are handled in the last IF.
  433. // if (FAILED(hr) && pViperCall). However, if Init ever returns an HR other than S_OK we
  434. // will need to place a return right here.
  435. if (FAILED(hr))
  436. {
  437. if (pViperCall)
  438. pViperCall->Release();
  439. return hr;
  440. }
  441. //
  442. // Make the locking of the light weight queue and the subsequent queuing to COM atomic
  443. //
  444. g_ViperReqMgr.LockQueue();
  445. hr = g_ViperReqMgr.AddReqObj(pViperCall);
  446. //
  447. // Assume that the ViperAsyncCall will succeed and set it the POSTed flag,
  448. // if it fails then cleanup. This avoids a race condition where the object is touched after we
  449. // have posted to request to Viper and it has deleted the object.
  450. //
  451. if (SUCCEEDED(hr))
  452. {
  453. pViperCall->SetAsyncCallPosted();
  454. hr = m_pActivity->AsynchronousCall(pViperCall);
  455. }
  456. //
  457. // We can release the lock as the request has now been queued to COM
  458. //
  459. g_ViperReqMgr.UnlockQueue();
  460. //
  461. // If we added it to the queue and the async call failed we have to be sure
  462. // that the watch thread did not remove the object off the light weight queue.
  463. // If RemoveReqObj returns false the watch thread has done the needful.
  464. //
  465. if (FAILED(hr) && g_ViperReqMgr.RemoveReqObj(pViperCall))
  466. { // cleanup if AsyncCall failed
  467. pViperCall->ClearAsyncCallPosted();
  468. pViperCall->Release();
  469. }
  470. return hr;
  471. }
  472. /*===================================================================
  473. CViperActivity::PostGlobalAsyncRequest
  474. Static method.
  475. Post async request without an activity.
  476. Creates temporary activity
  477. Parameters:
  478. CHitObj *pHitObj Denali's HitObj
  479. Returns:
  480. HRESULT
  481. ===================================================================*/
  482. HRESULT CViperActivity::PostGlobalAsyncRequest
  483. (
  484. CHitObj *pHitObj
  485. )
  486. {
  487. HRESULT hr = S_OK;
  488. CViperActivity *pTmpActivity = new CViperActivity;
  489. if (!pTmpActivity)
  490. hr = E_OUTOFMEMORY;
  491. if (SUCCEEDED(hr))
  492. hr = pTmpActivity->Init(pHitObj->PAppln()->PServicesConfig());
  493. if (SUCCEEDED(hr))
  494. {
  495. // remember this activity as HitObj's activity
  496. // HitObj will get rid of it on its destructor
  497. pHitObj->SetActivity(pTmpActivity);
  498. hr = pTmpActivity->PostAsyncRequest(pHitObj);
  499. pTmpActivity = NULL; // don't delete, HitObj will
  500. }
  501. if (pTmpActivity)
  502. delete pTmpActivity;
  503. return hr;
  504. }
  505. #ifdef DBG
  506. /*===================================================================
  507. CViperAsyncRequest::AssertValid
  508. Test to make sure that this is currently correctly formed
  509. and assert if it is not.
  510. Returns:
  511. ===================================================================*/
  512. void CViperActivity::AssertValid() const
  513. {
  514. Assert(FInited());
  515. Assert(m_pActivity);
  516. }
  517. #endif
  518. #ifdef UNUSED
  519. /*===================================================================
  520. C V i p e r T h r e a d E v e n t s
  521. ===================================================================*/
  522. /*===================================================================
  523. CViperThreadEvents::CViperThreadEvents
  524. CViperThreadEvents constructor
  525. Parameters:
  526. Returns:
  527. ===================================================================*/
  528. CViperThreadEvents::CViperThreadEvents()
  529. : m_cRefs(1)
  530. {
  531. }
  532. #ifdef DBG
  533. /*===================================================================
  534. CViperThreadEvents::AssertValid
  535. Test to make sure that this is currently correctly formed
  536. and assert if it is not.
  537. Returns:
  538. ===================================================================*/
  539. void CViperThreadEvents::AssertValid() const
  540. {
  541. Assert(m_cRefs > 0);
  542. Assert(ghDesktop != NULL);
  543. }
  544. #endif
  545. /*===================================================================
  546. CViperThreadEvents::QueryInterface
  547. Standard IUnknown method
  548. Parameters:
  549. REFIID iid
  550. void **ppv
  551. Returns:
  552. HRESULT
  553. ===================================================================*/
  554. STDMETHODIMP CViperThreadEvents::QueryInterface
  555. (
  556. REFIID iid,
  557. void **ppv
  558. )
  559. {
  560. if (iid == IID_IUnknown || iid == IID_IThreadEvents)
  561. {
  562. *ppv = this;
  563. AddRef();
  564. return S_OK;
  565. }
  566. return E_NOINTERFACE;
  567. }
  568. /*===================================================================
  569. CViperThreadEvents::AddRef
  570. Standard IUnknown method
  571. Parameters:
  572. Returns:
  573. Ref count
  574. ===================================================================*/
  575. STDMETHODIMP_(ULONG) CViperThreadEvents::AddRef()
  576. {
  577. DWORD cRefs = InterlockedIncrement((LPLONG)&m_cRefs);
  578. return cRefs;
  579. }
  580. /*===================================================================
  581. CViperThreadEvents::Release
  582. Standard IUnknown method
  583. Parameters:
  584. Returns:
  585. Ref count
  586. ===================================================================*/
  587. STDMETHODIMP_(ULONG) CViperThreadEvents::Release()
  588. {
  589. DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
  590. if (cRefs)
  591. return cRefs;
  592. delete this;
  593. return 0;
  594. }
  595. /*===================================================================
  596. CViperThreadEvents::OnStartup
  597. IThreadEvents method implementation. This method is called by Viper
  598. whenever they start up a thread.
  599. Parameters:
  600. None
  601. Returns:
  602. HRESULT
  603. ===================================================================*/
  604. STDMETHODIMP CViperThreadEvents::OnStartup()
  605. {
  606. HRESULT hr;
  607. AssertValid();
  608. // Set the desktop for this thread
  609. hr = SetDesktop();
  610. return hr;
  611. }
  612. /*===================================================================
  613. CViperThreadEvents::OnShutdown
  614. IThreadEvents method implementation. This method is called by Viper
  615. whenever they shut down a thread.
  616. Parameters:
  617. None
  618. Returns:
  619. HRESULT
  620. ===================================================================*/
  621. STDMETHODIMP CViperThreadEvents::OnShutdown()
  622. {
  623. AssertValid();
  624. return S_OK;
  625. }
  626. #endif //UNUSED
  627. /*===================================================================
  628. C V i p e r A c t i v i t y
  629. ===================================================================*/
  630. /*===================================================================
  631. CViperReqManager::CViperReqManager
  632. Parameters:
  633. Returns:
  634. VOID
  635. ===================================================================*/
  636. CViperReqManager::CViperReqManager()
  637. {
  638. m_dwReqObjs = 0;
  639. m_fCsInited = FALSE;
  640. m_fCsQueueInited = FALSE;
  641. m_fShutdown = FALSE;
  642. m_fDisabled = FALSE;
  643. m_hThreadAlive = NULL;
  644. m_hWakeUpEvent = NULL;
  645. }
  646. /*===================================================================
  647. CViperReqManager::Init
  648. Parameters:
  649. Returns:
  650. HRESULT
  651. ===================================================================*/
  652. HRESULT CViperReqManager::Init()
  653. {
  654. HRESULT hr = S_OK;
  655. DWORD dwRegValue;
  656. if (m_fDisabled == TRUE)
  657. return S_OK;
  658. m_dwQueueMin = Glob(dwRequestQueueMax) / (g_fOOP ? 5 : 10);
  659. m_dwLastAwakened = GetTickCount()/1000;
  660. m_dwQueueAlwaysWakeupMin = (Glob(dwRequestQueueMax)*80)/100;
  661. #if REFTRACE_VIPER_REQUESTS
  662. CViperAsyncRequest::gm_pTraceLog = CreateRefTraceLog(10000, 0);
  663. #endif
  664. ErrInitCriticalSection(&m_csLock, hr);
  665. if (SUCCEEDED(hr)) {
  666. m_fCsInited = TRUE;
  667. ErrInitCriticalSection(&m_csQueueLock, hr);
  668. if (SUCCEEDED(hr))
  669. {
  670. m_fCsQueueInited = TRUE;
  671. m_hWakeUpEvent = IIS_CREATE_EVENT("CViperReqManager::m_hWakeUpEvent",
  672. this,
  673. TRUE, // flag for manual-reset event
  674. FALSE); // flag for initial state
  675. if (!m_hWakeUpEvent)
  676. hr = E_OUTOFMEMORY;
  677. }
  678. }
  679. if (SUCCEEDED(hr)) {
  680. m_hThreadAlive = CreateThread(NULL, 0, CViperReqManager::WatchThread, 0, 0, NULL);
  681. if (!m_hThreadAlive) {
  682. hr = HRESULT_FROM_WIN32(GetLastError());
  683. }
  684. }
  685. if (FAILED(hr) && m_hWakeUpEvent)
  686. CloseHandle(m_hWakeUpEvent);
  687. if (SUCCEEDED(g_AspRegistryParams.GetF5AttackValue(&dwRegValue)))
  688. m_fDisabled = !dwRegValue;
  689. return hr;
  690. }
  691. /*===================================================================
  692. CViperReqManager::UnInit
  693. Parameters:
  694. Returns:
  695. HRESULT
  696. ===================================================================*/
  697. HRESULT CViperReqManager::UnInit()
  698. {
  699. HRESULT hr = S_OK;
  700. if (m_fDisabled == TRUE)
  701. return S_OK;
  702. // mark that we're in shutdown
  703. m_fShutdown = TRUE;
  704. #if REFTRACE_VIPER_REQUESTS
  705. DestroyRefTraceLog(CViperAsyncRequest::gm_pTraceLog);
  706. #endif
  707. // if the watch thread is still alive, wake it up and wait for
  708. // it to die off
  709. if (m_hThreadAlive)
  710. {
  711. WakeUp(TRUE);
  712. if (WaitForSingleObject (m_hThreadAlive, INFINITE) == WAIT_FAILED)
  713. {
  714. hr = HRESULT_FROM_WIN32(GetLastError());
  715. }
  716. CloseHandle (m_hThreadAlive);
  717. m_hThreadAlive = NULL;
  718. }
  719. if (m_fCsInited)
  720. {
  721. DeleteCriticalSection(&m_csLock);
  722. }
  723. if (m_fCsQueueInited)
  724. {
  725. DeleteCriticalSection(&m_csQueueLock);
  726. }
  727. if (m_hWakeUpEvent)
  728. CloseHandle(m_hWakeUpEvent);
  729. m_hWakeUpEvent = NULL;
  730. return hr;
  731. }
  732. /*===================================================================
  733. CViperReqManager::WatchThread
  734. Parameters:
  735. Returns:
  736. DWORD
  737. This thread is awakened to search for queued requests that should
  738. be tested to see if they still have connected clients on the other
  739. end.
  740. ::GetNext() is the key routine called to access a queued request.
  741. ::GetNext() will determine if there are requests that should be
  742. tested and return only those.
  743. ===================================================================*/
  744. DWORD __stdcall CViperReqManager::WatchThread(VOID *pArg)
  745. {
  746. DWORD dwReqsToTest = Glob(dwRequestQueueMax)/10;
  747. DWORD dwF5AttackThreshold = (Glob(dwRequestQueueMax)*90)/100;
  748. // live in a do-while loop
  749. do {
  750. CViperAsyncRequest *pViperReq = NULL;
  751. CViperAsyncRequest *pNextViperReq = NULL;
  752. BOOL fTestForF5Attack = FALSE;
  753. DWORD dwReqsDiscToCont = 0;
  754. DWORD dwReqsDisconnected = 0;
  755. DWORD dwReqsTested = 0;
  756. // wait for single object
  757. ResetEvent(g_ViperReqMgr.m_hWakeUpEvent);
  758. // check for shutdown
  759. if (g_ViperReqMgr.m_fShutdown)
  760. goto LExit;
  761. WaitForSingleObject(g_ViperReqMgr.m_hWakeUpEvent, INFINITE);
  762. g_ViperReqMgr.m_dwLastAwakened = GetTickCount()/1000;
  763. // check for shutdown
  764. if (g_ViperReqMgr.m_fShutdown)
  765. goto LExit;
  766. // determine the type of cleanup we're going to perform
  767. if (g_ViperReqMgr.m_dwReqObjs >= dwF5AttackThreshold) {
  768. // testing for a possible F5Attack. This will cause this loop
  769. // to test the most recently received requests to check for a large
  770. // number of disconnected requests. We'll test each 10% of the queue
  771. // to see if at least 75% of the requests are disconnected. If 75% or
  772. // more are disconnected, then we'll test the next 10%. If less than
  773. // 75%, then we aren't under an F5Attack and will stop testing for an
  774. // F5Attack.
  775. #if DEBUG_REQ_SCAVENGER
  776. DBGPRINTF((DBG_CONTEXT, "CViperReqManager::WatchThread - testing for F5Attack\r\n"));
  777. #endif
  778. fTestForF5Attack = TRUE;
  779. dwReqsDiscToCont = (dwReqsToTest * 75)/100;
  780. dwReqsDisconnected = 0;
  781. dwReqsTested = 0;
  782. }
  783. else {
  784. // not testing for F5Attack. We will test all requests that have
  785. // been on the queue for the minimum amount of time - 5 seconds if
  786. // inproc, else 10 seconds.
  787. #if DEBUG_REQ_SCAVENGER
  788. DBGPRINTF((DBG_CONTEXT, "CViperReqManager::WatchThread - NOT testing for F5Attack\r\n"));
  789. #endif
  790. fTestForF5Attack = FALSE;
  791. }
  792. // get the first request that is a candidate for testing
  793. pNextViperReq = g_ViperReqMgr.GetNext(NULL, fTestForF5Attack);
  794. // process all the available
  795. while (pViperReq = pNextViperReq) {
  796. // AddRef here to make sure the ViperReq object doesn't go away
  797. // on the STA thread underneath of us.
  798. pViperReq->AddRef();
  799. // check again for shutdown. GetNext() sets the testing
  800. // connection flag
  801. if (g_ViperReqMgr.m_fShutdown) {
  802. pViperReq->ClearTestingConnection();
  803. pViperReq->Release();
  804. goto LExit;
  805. }
  806. // if testing for F5Attack, check to see if we've tested the first
  807. // 10% of the requests on the list. If so, see if we've found that
  808. // 75% of them were disconnected. If not, then break. We're not under
  809. // attack. Otherwise, continue testing.
  810. if (fTestForF5Attack && (dwReqsTested == dwReqsToTest)) {
  811. if (dwReqsDisconnected < dwReqsDiscToCont) {
  812. #if DEBUG_REQ_SCAVENGER
  813. DBGPRINTF((DBG_CONTEXT, "CViperReqManager::WatchThread - 75% of requests NOT disconnected. Stopping.\r\n"));
  814. #endif
  815. // didn't see 75%, bail
  816. pViperReq->ClearTestingConnection();
  817. pViperReq->Release();
  818. break;
  819. }
  820. #if DEBUG_REQ_SCAVENGER
  821. DBGPRINTF((DBG_CONTEXT, "CViperReqManager::WatchThread - 75% of requests disconnected. Continuing.\r\n"));
  822. #endif
  823. // at least 75% were disconnected. Reset running counters
  824. // and continue
  825. dwReqsDisconnected = 0;
  826. dwReqsTested = 0;
  827. }
  828. dwReqsTested++;
  829. BOOL fConnected = TRUE;
  830. //
  831. // test the connection but do so only after we are sure it has been queued to COM
  832. //
  833. g_ViperReqMgr.LockQueue();
  834. if (!pViperReq->PHitObj()->PIReq()->TestConnection(&fConnected))
  835. fConnected = TRUE;
  836. g_ViperReqMgr.UnlockQueue();
  837. #if DEBUG_REQ_SCAVENGER
  838. DBGPRINTF((DBG_CONTEXT, "CViperReqManager::WatchThread. Tested - %S (%s) (%p,%p)\n",
  839. pViperReq->PHitObj()->PSzCurrTemplateVirtPath(),
  840. fConnected ? "TRUE" : "FALSE",
  841. pViperReq,
  842. pViperReq->PHitObj()));
  843. #endif
  844. // get the next request. This will leave two requests locked for
  845. // testing. We have to get the next request here because we may
  846. // remove it below.
  847. pNextViperReq = g_ViperReqMgr.GetNext(pViperReq,fTestForF5Attack);
  848. // now check fConnected
  849. if (!fConnected) {
  850. g_ReqDisconnected++;
  851. dwReqsDisconnected++;
  852. // not connected. Forceably remove the request from the queue.
  853. // Passing TRUE ignores the fTestingConnection test.
  854. DBG_REQUIRE(g_ViperReqMgr.RemoveReqObj(pViperReq,TRUE) == TRUE);
  855. // do the stuff we do in CHitObj::RejectBrowserRequestWhenNeeded().
  856. pViperReq->PHitObj()->SetFExecuting(FALSE);
  857. pViperReq->PHitObj()->ReportServerError(IDE_500_SERVER_ERROR);
  858. #ifndef PERF_DISABLE
  859. g_PerfData.Incr_REQCOMFAILED();
  860. g_PerfData.Decr_REQCURRENT();
  861. #endif
  862. delete pViperReq->PHitObj();
  863. }
  864. else {
  865. // still connected. Update the test stamp and release the testing
  866. // bit
  867. pViperReq->UpdateTestTimeStamp();
  868. pViperReq->ClearTestingConnection();
  869. }
  870. pViperReq->Release();
  871. }
  872. // we'll exit the loop here as well if shutdown becomes true.
  873. } while(g_ViperReqMgr.m_fShutdown == FALSE);
  874. LExit:
  875. //
  876. // the thread is going away.
  877. //
  878. return 0;
  879. }
  880. /*===================================================================
  881. CViperReqManager::AddReqObj
  882. Parameters:
  883. CViperAsyncRequest *pReqObj - request to add to queue
  884. Returns:
  885. HRESULT - always returns S_OK
  886. ===================================================================*/
  887. HRESULT CViperReqManager::AddReqObj(CViperAsyncRequest *pReqObj)
  888. {
  889. HRESULT hr = S_OK;
  890. #if DEBUG_REQ_SCAVENGER
  891. DWORD curObjs;
  892. #endif
  893. if (m_fDisabled == TRUE)
  894. return S_OK;
  895. // don't track non-browser requests
  896. if (pReqObj->FBrowserRequest() == FALSE)
  897. return S_OK;
  898. // lock the queue and add the object
  899. Lock();
  900. pReqObj->AppendTo(m_ReqObjList);
  901. m_dwReqObjs++;
  902. #if DEBUG_REQ_SCAVENGER
  903. curObjs = m_dwReqObjs;
  904. #endif
  905. Unlock();
  906. #if DEBUG_REQ_SCAVENGER
  907. DBGPRINTF((DBG_CONTEXT, "CViperReqManager::AddReqObj (%p). Total = %d\r\n", pReqObj, curObjs));
  908. #endif
  909. // for now, wake up the watch thread everytime.
  910. WakeUp();
  911. return hr;
  912. }
  913. /*===================================================================
  914. CViperReqManager::RemoveReqObj
  915. Parameters:
  916. CViperAsyncRequest *pReqObj - request to remove from the queue
  917. BOOL fForce - remove regardless of testing state
  918. Returns:
  919. BOOL - TRUE if req was on list, else FALSE
  920. ===================================================================*/
  921. BOOL CViperReqManager::RemoveReqObj(CViperAsyncRequest *pReqObj, BOOL fForce)
  922. {
  923. BOOL fOnList = FALSE;
  924. #if DEBUG_REQ_SCAVENGER
  925. DWORD curObjs;
  926. #endif
  927. if (m_fDisabled == TRUE)
  928. return TRUE;
  929. // if not a browser request, then this queue isn't tracking it.
  930. // It's safe to return TRUE
  931. if (pReqObj->FBrowserRequest() == FALSE)
  932. return TRUE;
  933. // can't remove the object from the queue if it is currently
  934. // being tested. The exception being if fForce is passed. This
  935. // is passed only by the WatchThread.
  936. sleepAgain:
  937. while((fForce != TRUE) && pReqObj->FTestingConnection())
  938. Sleep(100);
  939. // lock and remove the request
  940. Lock();
  941. // check to see if after we got the lock, the request is now
  942. // being tested. If so, unlock and return to sleeping.
  943. if ((fForce != TRUE) && pReqObj->FTestingConnection()) {
  944. Unlock();
  945. goto sleepAgain;
  946. }
  947. // now see if it's on the queue. If FIsEmpty(), then it's not
  948. // on the list.
  949. if (pReqObj->FIsEmpty()) {
  950. fOnList = FALSE;
  951. }
  952. else {
  953. // if it is, Unlink it. Call ClearTestingConnection to release
  954. // any other calls to RemoveReqObj that may be waiting. Of course
  955. // they all will see that the item is no longer on the list.
  956. fOnList = TRUE;
  957. pReqObj->UnLink();
  958. pReqObj->ClearTestingConnection();
  959. m_dwReqObjs--;
  960. }
  961. #if DEBUG_REQ_SCAVENGER
  962. curObjs = m_dwReqObjs;
  963. #endif
  964. Unlock();
  965. #if DEBUG_REQ_SCAVENGER
  966. DBGPRINTF((DBG_CONTEXT, "CViperReqManager::RemoveReqObj (%p). fOnList = %d; Total = %d\r\n", pReqObj, fOnList, curObjs));
  967. #endif
  968. // wakeup everytime for now...
  969. WakeUp();
  970. return fOnList;
  971. }
  972. /*===================================================================
  973. CViperReqManager::GetNext
  974. Parameters:
  975. CViperAsyncRequest *pLastReq - position in queue.
  976. Returns:
  977. CViperAsyncRequest* - non-NULL if request to test, else end of list
  978. ===================================================================*/
  979. CViperAsyncRequest *CViperReqManager::GetNext(CDblLink *pLastReq, BOOL fTestForF5Attack)
  980. {
  981. CViperAsyncRequest *pViperReq = NULL;
  982. // if NULL was passed in, then start from the head of the queue.
  983. if (pLastReq == NULL)
  984. pLastReq = &m_ReqObjList;
  985. // lock the queue while we find the next candidate
  986. Lock();
  987. if (fTestForF5Attack == TRUE) {
  988. // get the next request on the list
  989. pViperReq = static_cast<CViperAsyncRequest*>(pLastReq->PPrev());
  990. // enter a while loop until we either get to the end of the list or we find
  991. // a request has been posted to the viper queue
  992. while((pViperReq != &m_ReqObjList)
  993. && (pViperReq->FAsyncCallPosted() == FALSE))
  994. pViperReq = static_cast<CViperAsyncRequest*>(pViperReq->PPrev());
  995. }
  996. else {
  997. // get the next request on the list
  998. pViperReq = static_cast<CViperAsyncRequest*>(pLastReq->PNext());
  999. // enter a while loop until we either get to the end of the list or we find
  1000. // a request that hasn't been tested in dwTimeout() and has been posted
  1001. // to the viper queue
  1002. while((pViperReq != &m_ReqObjList)
  1003. && ((pViperReq->SecsSinceLastTest() < pViperReq->dwTimeout())
  1004. || (pViperReq->FAsyncCallPosted() == FALSE)))
  1005. pViperReq = static_cast<CViperAsyncRequest*>(pViperReq->PNext());
  1006. }
  1007. // if we found a candidate, set the TestingConnection flag
  1008. if (pViperReq != &m_ReqObjList) {
  1009. pViperReq->SetTestingConnection();
  1010. }
  1011. else {
  1012. // ended up at the queue head. Return NULL.
  1013. pViperReq = NULL;
  1014. }
  1015. Unlock();
  1016. return pViperReq;
  1017. }
  1018. /*===================================================================
  1019. G l o b a l F u n c t i o n s
  1020. ===================================================================*/
  1021. /*===================================================================
  1022. ViperSetContextProperty
  1023. Static utility function.
  1024. Set Viper context property by BSTR and IDispatch*.
  1025. The real interface takes BSTR and VARIANT.
  1026. Parameters
  1027. IContextProperties *pContextProperties Context
  1028. BSTR bstrPropertyName Name
  1029. IDispatch *pdispPropertyValue Value
  1030. Returns:
  1031. HRESULT
  1032. ===================================================================*/
  1033. static HRESULT ViperSetContextProperty
  1034. (
  1035. IContextProperties *pContextProperties,
  1036. BSTR bstrPropertyName,
  1037. IDispatch *pdispPropertyValue
  1038. )
  1039. {
  1040. // Make VARIANT from IDispatch*
  1041. pdispPropertyValue->AddRef();
  1042. VARIANT Variant;
  1043. VariantInit(&Variant);
  1044. V_VT(&Variant) = VT_DISPATCH;
  1045. V_DISPATCH(&Variant) = pdispPropertyValue;
  1046. // Call Viper to set the property
  1047. HRESULT hr = pContextProperties->SetProperty
  1048. (
  1049. bstrPropertyName,
  1050. Variant
  1051. );
  1052. // Cleanup
  1053. VariantClear(&Variant);
  1054. return hr;
  1055. }
  1056. /*===================================================================
  1057. ViperAttachIntrinsicsToContext
  1058. Attach ASP intrinsic objects as Viper context properties
  1059. Parameters - Intrinsics as interface pointers
  1060. IApplicationObject *pAppln Application (required)
  1061. ISessionObject *pSession Session (optional)
  1062. IRequest *pRequest Request (optional)
  1063. IResponse *pResponse Response (optional)
  1064. IServer *pServer Server (optional)
  1065. Returns:
  1066. HRESULT
  1067. ===================================================================*/
  1068. HRESULT ViperAttachIntrinsicsToContext
  1069. (
  1070. IApplicationObject *pAppln,
  1071. ISessionObject *pSession,
  1072. IRequest *pRequest,
  1073. IResponse *pResponse,
  1074. IServer *pServer
  1075. )
  1076. {
  1077. Assert(pAppln);
  1078. HRESULT hr = S_OK;
  1079. // Get Viper Context
  1080. IObjectContext *pViperContext = NULL;
  1081. hr = GetObjectContext(&pViperContext);
  1082. // Get IContextPoperties interface
  1083. IContextProperties *pContextProperties = NULL;
  1084. if (SUCCEEDED(hr))
  1085. hr = pViperContext->QueryInterface
  1086. (
  1087. IID_IContextProperties,
  1088. (void **)&pContextProperties
  1089. );
  1090. // Set properties
  1091. if (SUCCEEDED(hr))
  1092. hr = ViperSetContextProperty
  1093. (
  1094. pContextProperties,
  1095. BSTR_OBJ_APPLICATION,
  1096. pAppln
  1097. );
  1098. if (SUCCEEDED(hr) && pSession)
  1099. hr = ViperSetContextProperty
  1100. (
  1101. pContextProperties,
  1102. BSTR_OBJ_SESSION,
  1103. pSession
  1104. );
  1105. if (SUCCEEDED(hr) && pRequest)
  1106. hr = ViperSetContextProperty
  1107. (
  1108. pContextProperties,
  1109. BSTR_OBJ_REQUEST,
  1110. pRequest
  1111. );
  1112. if (SUCCEEDED(hr) && pResponse)
  1113. hr = ViperSetContextProperty
  1114. (
  1115. pContextProperties,
  1116. BSTR_OBJ_RESPONSE,
  1117. pResponse
  1118. );
  1119. if (SUCCEEDED(hr) && pServer)
  1120. hr = ViperSetContextProperty
  1121. (
  1122. pContextProperties,
  1123. BSTR_OBJ_SERVER,
  1124. pServer
  1125. );
  1126. // Cleanup
  1127. if (pContextProperties)
  1128. pContextProperties->Release();
  1129. if (pViperContext)
  1130. pViperContext->Release();
  1131. return hr;
  1132. }
  1133. /*===================================================================
  1134. ViperGetObjectFromContext
  1135. Get Viper context property by LPWSTR and
  1136. return it as IDispatch*.
  1137. The real interface takes BSTR and VARIANT.
  1138. Parameters
  1139. BSTR bstrName Property Name
  1140. IDispatch **ppdisp [out] Object (Property Value)
  1141. Returns:
  1142. HRESULT
  1143. ===================================================================*/
  1144. HRESULT ViperGetObjectFromContext
  1145. (
  1146. BSTR bstrName,
  1147. IDispatch **ppdisp
  1148. )
  1149. {
  1150. Assert(ppdisp);
  1151. HRESULT hr = S_OK;
  1152. // Get Viper Context
  1153. IObjectContext *pViperContext = NULL;
  1154. hr = GetObjectContext(&pViperContext);
  1155. // Get IContextPoperties interface
  1156. IContextProperties *pContextProperties = NULL;
  1157. if (SUCCEEDED(hr))
  1158. hr = pViperContext->QueryInterface
  1159. (
  1160. IID_IContextProperties,
  1161. (void **)&pContextProperties
  1162. );
  1163. // Get property Value as variant
  1164. VARIANT Variant;
  1165. VariantInit(&Variant);
  1166. if (SUCCEEDED(hr))
  1167. hr = pContextProperties->GetProperty(bstrName, &Variant);
  1168. // Convert Variant to IDispatch*
  1169. if (SUCCEEDED(hr))
  1170. {
  1171. IDispatch *pDisp = NULL;
  1172. if (V_VT(&Variant) == VT_DISPATCH)
  1173. pDisp = V_DISPATCH(&Variant);
  1174. if (pDisp)
  1175. {
  1176. pDisp->AddRef();
  1177. *ppdisp = pDisp;
  1178. }
  1179. else
  1180. hr = E_FAIL;
  1181. }
  1182. // Cleanup
  1183. VariantClear(&Variant);
  1184. if (pContextProperties)
  1185. pContextProperties->Release();
  1186. if (pViperContext)
  1187. pViperContext->Release();
  1188. if (FAILED(hr))
  1189. *ppdisp = NULL;
  1190. return hr;
  1191. }
  1192. /*===================================================================
  1193. ViperGetHitObjFromContext
  1194. Get Server from Viper context property and get
  1195. it's current HitObj
  1196. Parameters
  1197. CHitObj **ppHitObj [out]
  1198. Returns:
  1199. HRESULT
  1200. ===================================================================*/
  1201. HRESULT ViperGetHitObjFromContext
  1202. (
  1203. CHitObj **ppHitObj
  1204. )
  1205. {
  1206. *ppHitObj = NULL;
  1207. IDispatch *pdispServer = NULL;
  1208. HRESULT hr = ViperGetObjectFromContext(BSTR_OBJ_SERVER, &pdispServer);
  1209. if (FAILED(hr))
  1210. return hr;
  1211. if (pdispServer)
  1212. {
  1213. CServer *pServer = static_cast<CServer *>(pdispServer);
  1214. *ppHitObj = pServer->PHitObj();
  1215. pdispServer->Release();
  1216. }
  1217. return *ppHitObj ? S_OK : S_FALSE;
  1218. }
  1219. /*===================================================================
  1220. ViperCreateInstance
  1221. Viper's implementation of CoCreateInstance
  1222. Parameters
  1223. REFCLSID rclsid class id
  1224. REFIID riid interface
  1225. void **ppv [out] pointer to interface
  1226. Returns:
  1227. HRESULT
  1228. ===================================================================*/
  1229. HRESULT ViperCreateInstance
  1230. (
  1231. REFCLSID rclsid,
  1232. REFIID riid,
  1233. void **ppv
  1234. )
  1235. {
  1236. /*
  1237. DWORD dwClsContext = (Glob(fAllowOutOfProcCmpnts)) ?
  1238. CLSCTX_INPROC_SERVER | CLSCTX_SERVER :
  1239. CLSCTX_INPROC_SERVER;
  1240. */
  1241. // The reasons for supporting ASPAllowOutOfProcComponents seem to have
  1242. // vanished. Because this only partially worked in II4 and we changed
  1243. // the default in IIS5 this was causing problems with upgrades. So
  1244. // we're going to ignore the fAllowOutOfProcCmpnts setting.
  1245. DWORD dwClsContext = CLSCTX_INPROC_SERVER | CLSCTX_SERVER;
  1246. return CoCreateInstance(rclsid, NULL, dwClsContext, riid, ppv);
  1247. }
  1248. /*===================================================================
  1249. ViperConfigure
  1250. Viper settings: # of threads, queue len,
  1251. in-proc failfast,
  1252. allow oop components
  1253. Parameters
  1254. Returns:
  1255. HRESULT
  1256. ===================================================================*/
  1257. HRESULT ViperConfigure()
  1258. {
  1259. HRESULT hr = S_OK;
  1260. IMTSPackage *pPackage = NULL;
  1261. //
  1262. // Get hold of the package
  1263. //
  1264. hr = CoCreateInstance(CLSID_MTSPackage,
  1265. NULL,
  1266. CLSCTX_INPROC_SERVER,
  1267. IID_IMTSPackage,
  1268. (void **)&pPackage);
  1269. if (SUCCEEDED(hr) && !pPackage)
  1270. hr = E_FAIL;
  1271. //
  1272. // Bug 111008: Tell Viper that we do impersonations
  1273. //
  1274. if (SUCCEEDED(hr))
  1275. {
  1276. IImpersonationControl *pImpControl = NULL;
  1277. hr = pPackage->QueryInterface(IID_IImpersonationControl, (void **)&pImpControl);
  1278. if (SUCCEEDED(hr) && pImpControl)
  1279. {
  1280. hr = pImpControl->ClientsImpersonate(TRUE);
  1281. pImpControl->Release();
  1282. }
  1283. }
  1284. //
  1285. // Disable FAILFAST for in-proc case
  1286. //
  1287. if (SUCCEEDED(hr) && !g_fOOP)
  1288. {
  1289. IFailfastControl *pFFControl = NULL;
  1290. hr = pPackage->QueryInterface(IID_IFailfastControl, (void **)&pFFControl);
  1291. if (SUCCEEDED(hr) && pFFControl)
  1292. {
  1293. pFFControl->SetApplFailfast(FALSE);
  1294. pFFControl->Release();
  1295. }
  1296. }
  1297. /*
  1298. //
  1299. // Set Allow OOP Components
  1300. //
  1301. if (SUCCEEDED(hr))
  1302. {
  1303. INonMTSActivation *pNonMTSActivation = NULL;
  1304. hr = pPackage->QueryInterface(IID_INonMTSActivation, (void **)&pNonMTSActivation);
  1305. if (SUCCEEDED(hr) && pNonMTSActivation)
  1306. {
  1307. pNonMTSActivation->OutOfProcActivationAllowed(fAllowOopComponents);
  1308. pNonMTSActivation->Release();
  1309. }
  1310. }
  1311. */
  1312. //
  1313. // Clean-up
  1314. //
  1315. if (pPackage)
  1316. pPackage->Release();
  1317. return hr;
  1318. }
  1319. HRESULT ViperConfigureMTA()
  1320. {
  1321. HRESULT hr = S_OK;
  1322. IMTSPackage *pPackage = NULL;
  1323. if (g_fFirstMTAHit) {
  1324. EnterCriticalSection(&g_csFirstMTAHitLock);
  1325. if (g_fFirstMTAHit) {
  1326. //
  1327. // Get hold of the package
  1328. //
  1329. hr = CoCreateInstance(CLSID_MTSPackage,
  1330. NULL,
  1331. CLSCTX_INPROC_SERVER,
  1332. IID_IMTSPackage,
  1333. (void **)&pPackage);
  1334. if (SUCCEEDED(hr) && !pPackage)
  1335. hr = E_FAIL;
  1336. if (SUCCEEDED(hr)) {
  1337. IComMtaThreadPoolKnobs *pMTAKnobs = NULL;
  1338. hr = pPackage->QueryInterface(IID_IComMtaThreadPoolKnobs, (void **)&pMTAKnobs);
  1339. if (SUCCEEDED(hr) && pMTAKnobs) {
  1340. SYSTEM_INFO si;
  1341. GetSystemInfo(&si);
  1342. DWORD dwThreadCount;
  1343. if (FAILED(g_AspRegistryParams.GetTotalThreadMax(&dwThreadCount))) {
  1344. dwThreadCount = DEFAULT_MAX_THREAD;
  1345. }
  1346. if (dwThreadCount > Glob(dwProcessorThreadMax)*si.dwNumberOfProcessors) {
  1347. dwThreadCount = Glob(dwProcessorThreadMax)*si.dwNumberOfProcessors;
  1348. }
  1349. hr = pMTAKnobs->MTASetMaxThreadCount(dwThreadCount);
  1350. if (SUCCEEDED(hr))
  1351. hr = pMTAKnobs->MTASetThrottleValue(8);
  1352. pMTAKnobs->Release();
  1353. }
  1354. }
  1355. g_fFirstMTAHit = FALSE;
  1356. }
  1357. LeaveCriticalSection(&g_csFirstMTAHitLock);
  1358. }
  1359. return hr;
  1360. }
  1361. HRESULT ViperConfigureSTA()
  1362. {
  1363. HRESULT hr = S_OK;
  1364. IMTSPackage *pPackage = NULL;
  1365. if (g_fFirstSTAHit) {
  1366. EnterCriticalSection(&g_csFirstSTAHitLock);
  1367. if (g_fFirstSTAHit) {
  1368. //
  1369. // Get hold of the package
  1370. //
  1371. hr = CoCreateInstance(CLSID_MTSPackage,
  1372. NULL,
  1373. CLSCTX_INPROC_SERVER,
  1374. IID_IMTSPackage,
  1375. (void **)&pPackage);
  1376. if (SUCCEEDED(hr) && !pPackage)
  1377. hr = E_FAIL;
  1378. //
  1379. // Set knobs
  1380. //
  1381. if (SUCCEEDED(hr))
  1382. {
  1383. IComStaThreadPoolKnobs *pKnobs = NULL;
  1384. hr = pPackage->QueryInterface(IID_IComStaThreadPoolKnobs, (void **)&pKnobs);
  1385. if (SUCCEEDED(hr) && pKnobs)
  1386. {
  1387. // number of threads
  1388. SYSTEM_INFO si;
  1389. GetSystemInfo(&si);
  1390. DWORD dwThreadCount;
  1391. DWORD dwMinThreads;
  1392. if (FAILED(g_AspRegistryParams.GetTotalThreadMax(&dwThreadCount))) {
  1393. dwThreadCount = DEFAULT_MAX_THREAD;
  1394. }
  1395. if (dwThreadCount > Glob(dwProcessorThreadMax)*si.dwNumberOfProcessors) {
  1396. dwThreadCount = Glob(dwProcessorThreadMax)*si.dwNumberOfProcessors;
  1397. }
  1398. dwMinThreads = (si.dwNumberOfProcessors > 4) ? si.dwNumberOfProcessors : 4;
  1399. if (dwThreadCount < dwMinThreads) {
  1400. dwThreadCount = dwMinThreads;
  1401. }
  1402. pKnobs->SetMaxThreadCount(dwThreadCount);
  1403. pKnobs->SetMinThreadCount(dwMinThreads);
  1404. // queue length
  1405. pKnobs->SetQueueDepth(30000);
  1406. pKnobs->SetActivityPerThread(1);
  1407. pKnobs->Release();
  1408. }
  1409. }
  1410. // set Knobs2
  1411. if (SUCCEEDED(hr))
  1412. {
  1413. IComStaThreadPoolKnobs2 *pKnobs2 = NULL;
  1414. hr = pPackage->QueryInterface(IID_IComStaThreadPoolKnobs2, (void **)&pKnobs2);
  1415. if (SUCCEEDED(hr) && pKnobs2)
  1416. {
  1417. DWORD dwMaxCSR;
  1418. DWORD dwMaxCPU;
  1419. DWORD dwDisableCpuMetric;
  1420. if (SUCCEEDED(g_AspRegistryParams.GetMaxCPU(&dwMaxCPU))) {
  1421. pKnobs2->SetMaxCPULoad(dwMaxCPU);
  1422. }
  1423. else {
  1424. pKnobs2->SetMaxCPULoad(100);
  1425. }
  1426. if (SUCCEEDED(g_AspRegistryParams.GetMaxCSR(&dwMaxCSR))) {
  1427. pKnobs2->SetMaxCSR(dwMaxCSR);
  1428. }
  1429. if (SUCCEEDED(g_AspRegistryParams.GetDisableComPlusCpuMetric(&dwDisableCpuMetric))) {
  1430. pKnobs2->SetCPUMetricEnabled(!dwDisableCpuMetric);
  1431. }
  1432. pKnobs2->Release();
  1433. }
  1434. }
  1435. g_fFirstSTAHit = FALSE;
  1436. }
  1437. LeaveCriticalSection(&g_csFirstSTAHitLock);
  1438. }
  1439. return hr;
  1440. }
  1441. /*===================================================================
  1442. C O M H e l p e r A P I
  1443. ===================================================================*/
  1444. /*===================================================================
  1445. ViperCoObjectIsaProxy
  1446. Checks if the given IUnknown* points to a proxy
  1447. Parameters
  1448. IUnknown* pUnk pointer to check
  1449. Returns:
  1450. BOOL (TRUE if Proxy)
  1451. ===================================================================*/
  1452. BOOL ViperCoObjectIsaProxy
  1453. (
  1454. IUnknown* pUnk
  1455. )
  1456. {
  1457. HRESULT hr;
  1458. IUnknown *pUnk2;
  1459. hr = pUnk->QueryInterface(IID_IProxyManager, (void**)&pUnk2);
  1460. if (FAILED(hr))
  1461. return FALSE;
  1462. pUnk2->Release();
  1463. return TRUE;
  1464. }
  1465. /*===================================================================
  1466. ViperCoObjectAggregatesFTM
  1467. Checks if the given object agregates free threaded marshaller
  1468. (is agile)
  1469. Parameters
  1470. IUnknown* pUnk pointer to check
  1471. Returns:
  1472. BOOL (TRUE if Agile)
  1473. ===================================================================*/
  1474. BOOL ViperCoObjectAggregatesFTM
  1475. (
  1476. IUnknown *pUnk
  1477. )
  1478. {
  1479. HRESULT hr;
  1480. IMarshal *pMarshal;
  1481. GUID guidClsid;
  1482. hr = pUnk->QueryInterface(IID_IMarshal, (void**)&pMarshal);
  1483. if (FAILED(hr))
  1484. return FALSE;
  1485. hr = pMarshal->GetUnmarshalClass(IID_IUnknown, pUnk, MSHCTX_INPROC,
  1486. NULL, MSHLFLAGS_NORMAL, &guidClsid);
  1487. pMarshal->Release();
  1488. if (FAILED(hr))
  1489. return FALSE;
  1490. return (guidClsid == CLSID_InProcFreeMarshaler);
  1491. }