Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1041 lines
25 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name :
  4. wamobj.cxx
  5. Abstract:
  6. This module implements the WAM (web application manager) object
  7. Author:
  8. David Kaplan ( DaveK ) 26-Feb-1997
  9. Environment:
  10. User Mode - Win32
  11. Project:
  12. Wam DLL
  13. --*/
  14. /************************************************************
  15. * Include Headers
  16. ************************************************************/
  17. #include <isapip.hxx>
  18. #include "setable.hxx"
  19. # include "isapi.hxx"
  20. # include "WamW3.hxx"
  21. #include "wamobj.hxx"
  22. #include "iwr.h"
  23. #include "iwr_i.c"
  24. # include "timer.h"
  25. #include <irtlmisc.h>
  26. #include <ooptoken.h>
  27. // UNDONE where do these belong?
  28. extern PSE_TABLE g_psextensions;
  29. class CComContextHelper
  30. /*++
  31. Class description:
  32. Stack based helper class to enable calls to CoInitialize inside
  33. ISAPI.
  34. Replaces member functions PrepareCom/UnprepareCom in WAM_EXEC_INFO.
  35. These had to be replaced because WAM_EXEC_INFO will persist beyond
  36. the initial ISAPI call in the async case and keeping the call context
  37. in member data would leak and overrelease under certain conditions.
  38. Public Interface:
  39. PrepareCom : For OOP get the call context and use our
  40. private interface to enable coinit calls.
  41. UnprepareCom : Release the call context.
  42. --*/
  43. {
  44. public:
  45. CComContextHelper( BOOL fInProcess )
  46. : m_fInProcess( fInProcess ),
  47. m_pComContext( NULL ),
  48. m_pComInitsCookie( NULL )
  49. {
  50. }
  51. ~CComContextHelper( void )
  52. {
  53. UnprepareCom();
  54. }
  55. HRESULT PrepareCom()
  56. /*++
  57. Routine Description:
  58. Prepare com before call into ISAPI. For OOP get the call context
  59. and use our private interface to enable coinit calls.
  60. --*/
  61. {
  62. HRESULT hr = NOERROR;
  63. // Never call twice.
  64. DBG_ASSERT( NULL == m_pComInitsCookie );
  65. DBG_ASSERT( NULL == m_pComContext );
  66. if( !m_fInProcess )
  67. {
  68. // Save COM Call Context in MTS case
  69. hr = CoGetCallContext( IID_IComDispatchInfo, (void **)&m_pComContext );
  70. if( SUCCEEDED(hr) )
  71. {
  72. hr = m_pComContext->EnableComInits( &m_pComInitsCookie );
  73. }
  74. }
  75. return hr;
  76. }
  77. void UnprepareCom()
  78. /*++
  79. Routine Description:
  80. Restores com state after call into ISAPI. Release call context.
  81. --*/
  82. {
  83. // Restore COM Call Context
  84. if( m_pComContext )
  85. {
  86. DBG_ASSERT( !m_fInProcess );
  87. DBG_ASSERT( m_pComInitsCookie );
  88. m_pComContext->DisableComInits( m_pComInitsCookie );
  89. m_pComContext->Release();
  90. m_pComContext = NULL;
  91. m_pComInitsCookie = NULL;
  92. }
  93. }
  94. private:
  95. //NO-OP
  96. CComContextHelper() {}
  97. CComContextHelper( const CComContextHelper & ref ) {}
  98. private:
  99. BOOL m_fInProcess;
  100. IComDispatchInfo * m_pComContext;
  101. void * m_pComInitsCookie;
  102. };
  103. /*---------------------------------------------------------------------*
  104. WAM::InitWam
  105. Routine Description:
  106. Initializes this WAM.
  107. Arguments:
  108. See below
  109. Return Value:
  110. HRESULT
  111. */
  112. STDMETHODIMP
  113. WAM::InitWam
  114. (
  115. BOOL fInProcess, // are we in-proc or out-of-proc?
  116. BOOL fInPool, // !Isolated
  117. BOOL fEnableTryExcept, // catch exceptions in ISAPI calls?
  118. int pt, // PLATFORM_TYPE - are we running on Win95?
  119. DWORD *pPID // Process Id of the process the wam was created in
  120. )
  121. {
  122. HRESULT hr = NOERROR;
  123. IF_DEBUG( INIT_CLEAN ) {
  124. DBGPRINTF(( DBG_CONTEXT,
  125. "\n ********** WAM(%08x)::InitWam() *****\n",
  126. this));
  127. }
  128. INITIALIZE_CRITICAL_SECTION( &m_csWamExecInfoList );
  129. InitializeListHead( &m_WamExecInfoListHead );
  130. m_fInProcess = fInProcess;
  131. m_fInPool = fInPool;
  132. DBG_ASSERT( pt != PtInvalid );
  133. m_pt = (PLATFORM_TYPE) pt;
  134. // Get the process id of the current process so we can return it to w3svc
  135. *pPID = GetCurrentProcessId();
  136. // Acquire a reference to the SE_TABLE object
  137. DBG_REQUIRE( g_psextensions->AddRefWam() > 0);
  138. IF_DEBUG( INIT_CLEAN) {
  139. DBGPRINTF(( DBG_CONTEXT, "\n************Leaving WAM::InitWam ...\n" ));
  140. }
  141. DBG_ASSERT( SUCCEEDED(hr));
  142. //
  143. // UNDONE: See the DoGlobalInitializations() for details.
  144. //
  145. hr = DoGlobalInitializations( fInProcess, fEnableTryExcept);
  146. return (hr);
  147. } // WAM::InitWam()
  148. /*---------------------------------------------------------------------*
  149. WAM::StartShutdown
  150. Routine Description:
  151. Phase 1 of shutdown process.
  152. Set the shutdown flag on the WAM object
  153. Loop for small duration checking if all WAM_EXEC_INFO's have drained.
  154. At the end of loop initiate the first phase of TerminateExtension()
  155. NOTE: TerminateExtension() - currently have been tested only for the
  156. MUST_UNLOAD option => there is no two-phase operation there.
  157. So, we will rely on calling it once only.
  158. Arguments:
  159. None
  160. Return Value:
  161. HRESULT
  162. */
  163. STDMETHODIMP
  164. WAM::StartShutdown(
  165. )
  166. {
  167. DWORD i;
  168. IF_DEBUG( WAM ) {
  169. DBGPRINTF(( DBG_CONTEXT,
  170. "WAM(%08x)::StartShutdown() %d Active Requests\n",
  171. this, QueryWamStats().QueryCurrentWamRequests() ));
  172. }
  173. // Set the Shutting down flag to true now
  174. DBG_REQUIRE( FALSE ==
  175. InterlockedExchange((LPLONG)&m_fShuttingDown, (LONG)TRUE)
  176. );
  177. for ( i = 0;
  178. ( (i < 10) &&
  179. (QueryWamStats().QueryCurrentWamRequests())
  180. );
  181. i++ )
  182. {
  183. # ifndef SHUTOFF_AFTER_BETA
  184. DBGPRINTF( (
  185. DBG_CONTEXT,
  186. "[%d] WAM(%08x) has %d requests waiting for cleanup\n",
  187. GetCurrentThreadId(),
  188. this, QueryWamStats().QueryCurrentWamRequests()
  189. ) );
  190. # endif // SHUTOFF_AFTER_BETA
  191. Sleep( 200 ); // sleep for a while before restarting the check again
  192. } // for
  193. // Release the reference to the SE_TABLE object
  194. g_psextensions->ReleaseRefWam();
  195. return NOERROR;
  196. } // WAM::StartShutdown()
  197. /*---------------------------------------------------------------------*
  198. WAM::UninitWam
  199. Routine Description:
  200. Phase 2 of shutdown process.
  201. Arguments:
  202. None
  203. Return Value:
  204. HRESULT
  205. NOERROR on success
  206. E_FAIL if there are any pending items to be deleted still
  207. */
  208. STDMETHODIMP
  209. WAM::UninitWam()
  210. {
  211. //
  212. // If there are any pending requests being processed, wait for them
  213. // to be drained off from this WAM
  214. //
  215. IF_DEBUG( WAM ) {
  216. DBGPRINTF(( DBG_CONTEXT,
  217. "WAM(%08x)::UninitWam() %d Active Requests\n",
  218. this, QueryWamStats().QueryCurrentWamRequests() ));
  219. }
  220. if ( QueryWamStats().QueryCurrentWamRequests() != 0 )
  221. {
  222. IF_DEBUG( ERROR) {
  223. DBGPRINTF(( DBG_CONTEXT,
  224. "WAM(%08x)::UninitWam() Error - "
  225. " Failed with active requests! (%d active)\n",
  226. this,
  227. QueryWamStats().QueryCurrentWamRequests() ));
  228. }
  229. //
  230. // Enumerate and dump information on all requests that are hanging
  231. // and the associated ISAPI DLLs
  232. //
  233. # ifndef SHUTOFF_AFTER_BETA
  234. while ( QueryWamStats().QueryCurrentWamRequests() > 0) {
  235. DBGPRINTF(
  236. ( DBG_CONTEXT,
  237. "\n\n[Thd %d]WAM(%08x) has %d requests waiting ... \n",
  238. GetCurrentThreadId(),
  239. this, QueryWamStats().QueryCurrentWamRequests()
  240. ) );
  241. g_psextensions->PrintRequestCounts();
  242. // sleep for a while before restarting the check again
  243. Sleep( 1000 );
  244. } // while
  245. # endif // SHUTOFF_AFTER_BETA
  246. // return failure, since we failed to shutdown gracefully!
  247. // NYI: Should I ignore the fact that some long-hanging connections
  248. // are okay?
  249. // Shouldn't I be forcing the exit now?
  250. DBG_ASSERT( QueryWamStats().QueryCurrentWamRequests() == 0);
  251. // return ( E_FAIL);
  252. }
  253. DeleteCriticalSection( &m_csWamExecInfoList );
  254. return NOERROR;
  255. } // WAM::UninitWam()
  256. /*-----------------------------------------------------------------------------*
  257. WAM::ProcessAsyncIO
  258. Completes an async i/o process for a given wam request.
  259. Arguments:
  260. Return Value:
  261. HRESULT
  262. */
  263. STDMETHODIMP
  264. WAM::ProcessAsyncIO
  265. (
  266. #ifdef _WIN64
  267. UINT64 pWamExecInfoIn, // WAM_EXEC_INFO *
  268. #else
  269. DWORD_PTR pWamExecInfoIn, // WAM_EXEC_INFO *
  270. #endif
  271. DWORD dwStatus,
  272. DWORD cbWritten
  273. )
  274. {
  275. return ProcessAsyncIOImpl( pWamExecInfoIn,
  276. dwStatus,
  277. cbWritten
  278. );
  279. } // WAM::ProcessAsyncIO
  280. STDMETHODIMP
  281. WAM::ProcessAsyncReadOop
  282. (
  283. #ifdef _WIN64
  284. UINT64 pWamExecInfoIn,
  285. #else
  286. DWORD_PTR pWamExecInfoIn,
  287. #endif
  288. DWORD dwStatus,
  289. DWORD cbRead,
  290. unsigned char * lpDataRead
  291. )
  292. /*++
  293. Routine Description:
  294. Handle callback for out of process AsyncRead
  295. Arguments:
  296. pWamExecInfoIn - The smuggled pointer to the WAM_EXEC_INFO
  297. dwStatus - IO status
  298. cbRead - Number of bytes read
  299. lpDataRead - Marshalled data read
  300. Return Value:
  301. Notes:
  302. The initial design for AsyncRead was inadequate when the isapi is
  303. running out of process. The problem was that the data buffer was
  304. marshalled over to inetinfo and back during the AsyncRead call.
  305. Since the completion will happen on another thread the ISAPI could
  306. get the completion before the data was completely marshalled back
  307. or the address in inetinfo could be invalidated before the read was
  308. complete. The solution is to add a separate path for oop async reads
  309. and marshall the data on the io completion and copy it into the
  310. client's buffer then.
  311. --*/
  312. {
  313. DBG_ASSERT( lpDataRead != NULL );
  314. DBG_ASSERT( !m_fInProcess );
  315. return ProcessAsyncIOImpl( pWamExecInfoIn,
  316. dwStatus,
  317. cbRead,
  318. lpDataRead
  319. );
  320. }
  321. HRESULT
  322. WAM::ProcessAsyncIOImpl
  323. (
  324. #ifdef _WIN64
  325. UINT64 pWamExecInfoIn,
  326. #else
  327. DWORD_PTR pWamExecInfoIn,
  328. #endif
  329. DWORD dwStatus,
  330. DWORD cb,
  331. LPBYTE lpDataRead // = NULL
  332. )
  333. {
  334. HRESULT hrRet;
  335. CComContextHelper callContext( m_fInProcess );
  336. WAM_EXEC_INFO * pWamExecInfo =
  337. reinterpret_cast<WAM_EXEC_INFO *>(pWamExecInfoIn);
  338. //
  339. // NOTE we assert because we believe the pointer can never be null
  340. // AND we fail gracefully if it is null because there is a long
  341. // code path across many threads between setting the pointer
  342. // and here, and you never know ...
  343. //
  344. DBG_ASSERT ( pWamExecInfo != NULL );
  345. if ( pWamExecInfo == NULL ) {
  346. return HRESULT_FROM_WIN32( E_POINTER );
  347. }
  348. //
  349. // Note: The AddRef/Release calls may not be necessary anymore.
  350. //
  351. // Make sure that UnprepareCom has valid WamInfo
  352. //
  353. pWamExecInfo->AddRef();
  354. callContext.PrepareCom();
  355. if( lpDataRead == NULL )
  356. {
  357. // Doing an out of process async read
  358. hrRet = HresultFromBool(
  359. pWamExecInfo->ProcessAsyncIO(
  360. dwStatus,
  361. cb
  362. ) );
  363. }
  364. else
  365. {
  366. // All other async io completions
  367. hrRet = HresultFromBool(
  368. pWamExecInfo->ProcessAsyncReadOop(
  369. dwStatus,
  370. cb,
  371. lpDataRead
  372. ) );
  373. }
  374. callContext.UnprepareCom();
  375. //
  376. // Balance AddRef() above
  377. //
  378. pWamExecInfo->Release();
  379. return hrRet;
  380. }
  381. /*-----------------------------------------------------------------------------*
  382. WAM::ProcessRequest
  383. Processes a WAM request.
  384. Arguments:
  385. pIWamRequest - pointer to IWamRequest interface
  386. cbWrcStrings - Count of bytes for wamreq core strings
  387. pfHandled - Indicates we handled this request
  388. pfFinished - Indicates no further processing is required
  389. Return Value:
  390. HRESULT
  391. */
  392. STDMETHODIMP
  393. WAM::ProcessRequest
  394. (
  395. IWamRequest * pIWamRequest,
  396. DWORD cbWrcStrings,
  397. OOP_CORE_STATE * pOopCoreState,
  398. BOOL * pfHandled
  399. )
  400. {
  401. HRESULT hrRet = NOERROR; // this function's return value
  402. HRESULT hr;
  403. int iretInvokeExt; // return value from InvokeExtension
  404. BOOL fFreeContext = TRUE;// do we need to free up wamex-info?
  405. WAM_EXEC_INFO * pWamExecInfo = NULL;
  406. BOOL fImpersonated = FALSE;
  407. BYTE * pbEntityBody = NULL;
  408. DWORD cbEntityBody = 0;
  409. CComContextHelper callContext( m_fInProcess );
  410. DBG_ASSERT( pIWamRequest );
  411. IF_DEBUG( WAM) {
  412. DBGPRINTF(( DBG_CONTEXT,
  413. "WAM(%08x)::ProcessRequest(%08x, %08x, ... )\n",
  414. this, pIWamRequest ));
  415. }
  416. if ( m_fShuttingDown ) {
  417. IF_DEBUG( WAM) {
  418. DBGPRINTF((
  419. DBG_CONTEXT
  420. , "WAM(%08x) shutting down. "
  421. "Request(%08x) will be aborted.\n"
  422. , this
  423. , pIWamRequest
  424. ));
  425. }
  426. // UNDONE something besides E_FAIL?
  427. return E_FAIL;
  428. }
  429. // create, init the wamexec-info and add it to list
  430. pWamExecInfo = new WAM_EXEC_INFO( this );
  431. if( NULL == pWamExecInfo )
  432. {
  433. hrRet = E_OUTOFMEMORY;
  434. goto LError;
  435. }
  436. //
  437. // Update the statistics counters
  438. //
  439. m_WamStats.IncrWamRequests();
  440. if ( FAILED( hrRet = pWamExecInfo->InitWamExecInfo( pIWamRequest,
  441. cbWrcStrings,
  442. pOopCoreState
  443. ) ) )
  444. {
  445. goto LError;
  446. }
  447. if( !m_fInProcess )
  448. {
  449. //
  450. // This test shouldn't really be necessary. In the case where com plus
  451. // activates us in process even if we are marked to run in the
  452. // surrogate, we will fail the app creation.
  453. //
  454. DBG_ASSERT( CWamOopTokenInfo::HasInstance() );
  455. if( CWamOopTokenInfo::HasInstance() )
  456. {
  457. hrRet = CWamOopTokenInfo::QueryInstance()->ModifyTokenForOop
  458. (
  459. WRC_GET_FIX.m_hUserToken
  460. );
  461. if( FAILED(hrRet) )
  462. {
  463. goto LError;
  464. }
  465. }
  466. }
  467. this->InsertIntoList( &pWamExecInfo->_ListEntry);
  468. DBG_WAMREQ_REFCOUNTS(( "WAM::ProcessRequest right after wrc construction ...", pWamExecInfo ));
  469. if ( !FWin95() )
  470. {
  471. if ( !ImpersonateLoggedOnUser( WRC_GET_FIX.m_hUserToken ) )
  472. {
  473. IF_DEBUG( ERROR ) {
  474. DBGPRINTF((DBG_CONTEXT,
  475. "WAM(%08x) ImpersonateLoggedOnUser(%08x)"
  476. "failed[err %d]\n",
  477. this, WRC_GET_FIX.m_hUserToken, GetLastError()));
  478. }
  479. hrRet = HresultFromGetLastError();
  480. goto LError;
  481. }
  482. fImpersonated = TRUE;
  483. }
  484. pWamExecInfo->_psExtension = NULL;
  485. if ( ! g_psextensions->GetExtension( WRC_GET_SZ( WRC_I_ISADLLPATH ),
  486. WRC_GET_FIX.m_hUserToken,
  487. WRC_GET_FIX.m_fAnonymous,
  488. WRC_GET_FIX.m_fCacheISAPIApps,
  489. &(pWamExecInfo->_psExtension ) ) )
  490. {
  491. hrRet = HresultFromGetLastError( );
  492. goto LError;
  493. }
  494. // Add a reference to ensure that wamexec is valid until we hit the
  495. // cleanup code. Don't put any goto LError after this or the wamexec
  496. // will leak.
  497. pWamExecInfo->AddRef();
  498. // Invoke the server extension
  499. callContext.PrepareCom();
  500. iretInvokeExt = InvokeExtension( pWamExecInfo->_psExtension,
  501. WRC_GET_SZ( WRC_I_ISADLLPATH ),
  502. pWamExecInfo );
  503. callContext.UnprepareCom();
  504. if ( fImpersonated ) {
  505. ::RevertToSelf( );
  506. fImpersonated = FALSE;
  507. }
  508. pWamExecInfo->_dwFlags &= ~SE_PRIV_FLAG_IN_CALLBACK;
  509. switch ( iretInvokeExt )
  510. {
  511. case HSE_STATUS_PENDING: {
  512. IF_DEBUG( WAM_EXEC ) {
  513. DBGPRINTF((
  514. DBG_CONTEXT
  515. , "WAM(%08x)::ProcessRequest case HSE_STATUS_PENDING\n"
  516. , this
  517. ));
  518. }
  519. IF_DEBUG( WAM_REFCOUNTS ) {
  520. DBG_WAMREQ_REFCOUNTS((
  521. "WAM::ProcessRequest case HSE_STATUS_PENDING ",
  522. pWamExecInfo
  523. ));
  524. }
  525. //
  526. // Figure out whether this mainline thread or callback thread
  527. // hit its cleanup code first
  528. //
  529. // This protects us against isapis that disobey the async rules.
  530. // The isapi should be in one of two modes:
  531. //
  532. // 1. It return HSE_STATUS_PENDING in the mainline thread and
  533. // always calls HSE_DONE_WITH_SESSION.
  534. //
  535. // 2. It returns any other status code from the mainline and
  536. // NEVER calls HSE_DONE_WITH_SESSION.
  537. //
  538. // Unfortunately isapi writers frequently do bad things to good
  539. // servers.
  540. //
  541. // NOTE return value of INTERLOCKED_COMPARE_EXCHANGE
  542. // is initial value of the destination
  543. //
  544. LONG FirstThread = INTERLOCKED_COMPARE_EXCHANGE(
  545. (LONG *) &pWamExecInfo->_FirstThread
  546. , (LONG) FT_MAINLINE
  547. , (LONG) FT_NULL
  548. );
  549. if( FirstThread == (LONG) FT_CALLBACK ) {
  550. //
  551. // If we made it here, then we need to do cleanup, meaning:
  552. // - SSF HSE_REQ_DONE_WITH_SESSION callback has already run
  553. // - we set fFreeContext TRUE to trigger cleanup below
  554. //
  555. fFreeContext = TRUE;
  556. IF_DEBUG( WAM_EXEC ) {
  557. DBGPRINTF((
  558. DBG_CONTEXT
  559. , "\tSession done.\n"
  560. ));
  561. }
  562. } else {
  563. DBG_ASSERT( FirstThread == (LONG) FT_NULL );
  564. //
  565. // If we made it here, then we can't cleanup yet, meaning:
  566. // - SSF HSE_REQ_DONE_WITH_SESSION callback will cleanup
  567. // when it runs
  568. // - we set fFreeContext FALSE to avoid cleanup below
  569. //
  570. fFreeContext = FALSE;
  571. IF_DEBUG( WAM_EXEC ) {
  572. DBGPRINTF((
  573. DBG_CONTEXT
  574. , "\tSession NOT done.\n"
  575. ));
  576. }
  577. }
  578. //
  579. // If fFreeContext is FALSE at this point, we may not use
  580. // pWamExecInfo from this point on - callback thread can
  581. // invalidate it at any time.
  582. //
  583. break;
  584. } // case HSE_STATUS_PENDING
  585. case HSE_STATUS_ERROR:
  586. case HSE_STATUS_SUCCESS:
  587. //
  588. // in error and success cases we no-op
  589. //
  590. break;
  591. case HSE_STATUS_SUCCESS_AND_KEEP_CONN:
  592. //
  593. // remember that ISA asked us to set keep-conn
  594. //
  595. pWamExecInfo->_dwIsaKeepConn = KEEPCONN_TRUE;
  596. break;
  597. default:
  598. break;
  599. } // switch()
  600. // Release the ref held by this call
  601. pWamExecInfo->Release();
  602. if ( fFreeContext ) {
  603. DBG_ASSERT( pWamExecInfo != NULL);
  604. DBG_WAMREQ_REFCOUNTS(( "WAM::ProcessRequest fFreeContext ...",
  605. pWamExecInfo));
  606. pWamExecInfo->CleanupAndRelease( TRUE );
  607. pWamExecInfo = NULL;
  608. } // if ( fFreeContext);
  609. *pfHandled = TRUE;
  610. DBG_ASSERT( hrRet == NOERROR );
  611. LExit:
  612. if ( fImpersonated ) {
  613. ::RevertToSelf( );
  614. fImpersonated = FALSE;
  615. }
  616. return hrRet;
  617. LError:
  618. //
  619. // release pWamExecInfo on failure case
  620. // NOTE we separate this from normal exit code because wamexecinfo
  621. // must hang around in many non-error cases (status-pending, async i/o)
  622. //
  623. if ( pWamExecInfo != NULL) {
  624. pWamExecInfo->CleanupAndRelease( FALSE );
  625. pWamExecInfo = NULL;
  626. }
  627. goto LExit;
  628. } // WAM::ProcessRequest()
  629. STDMETHODIMP
  630. WAM::GetStatistics(
  631. /*[in]*/ DWORD dwLevel,
  632. /*[out, switch_is(Level)]*/
  633. LPWAM_STATISTICS_INFO pWamStatsInfo
  634. )
  635. /*++
  636. Description:
  637. Obtains the statistics for the given instance of WAM for specified level.
  638. Arguments:
  639. dwLevel - specifies the information level. (Currently level 0 is supported)
  640. pWamStatsInfo - pointer to the WAM STATISTICS INFO object that will
  641. receive the statistics.
  642. Returns:
  643. HRESULT - NOERROR on success and E_FAIL on failure.
  644. --*/
  645. {
  646. HRESULT hr = NOERROR;
  647. DBG_ASSERT( pWamStatsInfo != NULL);
  648. IF_DEBUG( API_ENTRY) {
  649. DBGPRINTF(( DBG_CONTEXT, "WAM(%08x)::GetStatistics(%d, %08x)\n",
  650. this, dwLevel, pWamStatsInfo));
  651. }
  652. switch ( dwLevel) {
  653. case 0: {
  654. // copy values out of the statistics structure
  655. m_WamStats.CopyToStatsBuffer( &pWamStatsInfo->WamStats0);
  656. break;
  657. }
  658. default:
  659. DBG_ASSERT( FALSE);
  660. hr = E_FAIL;
  661. break;
  662. } // switch()
  663. return (hr);
  664. } // WAM::GetStatistics()
  665. /*++
  666. WAM::InvokeExtension
  667. Routine Description:
  668. Invokes a server extension.
  669. NOTE without this cover function, we get a compile error
  670. error C2712: Cannot use __try in functions that require object unwinding
  671. Arguments:
  672. psExt - pointer to server extension
  673. szISADllPath - Fully qualified path to Module (DLL name)
  674. pWamExecInfo - ptr to wamexec info
  675. Return Value:
  676. DWORD - HSE_STATUS_ code
  677. --*/
  678. DWORD
  679. WAM::InvokeExtension
  680. (
  681. IN PHSE psExt,
  682. const char * szISADllPath,
  683. WAM_EXEC_INFO * pWamExecInfo
  684. )
  685. {
  686. DWORD ret;
  687. //
  688. // Protect the call to the server extension so we don't hose the
  689. // server
  690. //
  691. __try
  692. {
  693. ret = psExt->ExecuteRequest( pWamExecInfo );
  694. }
  695. __except ( g_fEnableTryExcept ?
  696. WAMExceptionFilter( GetExceptionInformation(),
  697. WAM_EVENT_EXTENSION_EXCEPTION,
  698. pWamExecInfo ) :
  699. EXCEPTION_CONTINUE_SEARCH )
  700. {
  701. //
  702. // exception caused us to to leave HSE_APPDLL::ExecuteRequest
  703. // with unbalanced AddRef()
  704. //
  705. pWamExecInfo->Release();
  706. ret = HSE_STATUS_ERROR;
  707. }
  708. return ret;
  709. } // WAM::InvokeExtension
  710. /*++
  711. WAM::HseReleaseExtension
  712. Routine Description:
  713. Releases a server extension.
  714. Arguments:
  715. psExt - pointer to server extension.
  716. Return Value:
  717. None
  718. --*/
  719. VOID
  720. WAM::HseReleaseExtension
  721. (
  722. IN PHSE psExt
  723. )
  724. {
  725. g_psextensions->ReleaseExtension( psExt);
  726. } // HseReleaseExtension()
  727. /************************************************************
  728. * Member Functions of WAM_STATISTICS
  729. ************************************************************/
  730. WAM_STATISTICS::WAM_STATISTICS( VOID)
  731. /*++
  732. Initializes statistics information for server.
  733. --*/
  734. {
  735. INITIALIZE_CRITICAL_SECTION( & m_csStatsLock);
  736. ClearStatistics();
  737. } // WAM_STATISTICS::WAM_STATISTICS();
  738. VOID
  739. WAM_STATISTICS::ClearStatistics( VOID)
  740. /*++
  741. Clears the counters used for statistics information
  742. --*/
  743. {
  744. LockStatistics();
  745. memset( &m_WamStats, 0, sizeof(WAM_STATISTICS_0) );
  746. m_WamStats.TimeOfLastClear = GetCurrentTimeInSeconds();
  747. UnlockStatistics();
  748. } // WAM_STATISTICS::ClearStatistics()
  749. DWORD
  750. WAM_STATISTICS::CopyToStatsBuffer( PWAM_STATISTICS_0 pStat0)
  751. /*++
  752. Description:
  753. copies the statistics data from the server statistcs structure
  754. to the WAM_STATISTICS_0 structure for RPC access.
  755. Arugments:
  756. pStat0 pointer to WAM_STATISTICS_0 object which contains the
  757. data on successful return
  758. Returns:
  759. Win32 error codes. NO_ERROR on success.
  760. --*/
  761. {
  762. DBG_ASSERT( pStat0 != NULL);
  763. LockStatistics();
  764. CopyMemory( pStat0, &m_WamStats, sizeof(WAM_STATISTICS_0) );
  765. UnlockStatistics();
  766. return ( NO_ERROR);
  767. } // WAM_STATISTICS::CopyToStatsBuffer()
  768. /************************ End of File ***********************/