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.

1344 lines
34 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // HTTPXPC.CXX
  4. //
  5. // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  6. //
  7. // Monitor-side for W3 integration.
  8. //
  9. #include "w3p.hxx" // W3SVC Precompiled header
  10. #include <windows.h>
  11. #include <winperf.h>
  12. #include "pclib.hxx"
  13. #include "httpxctr.hxx" // Perf counter title index #defines
  14. #include "caldbg.h" // For DebugTrace()/Assert()
  15. EXTERN_C const WCHAR gc_wszSignature[] = L"HTTPEXT";
  16. EXTERN_C const CHAR gc_szDbgIni[] = "HTTPXPC.INI";
  17. EXTERN_C const INT gc_cchDbgIni = 11;
  18. EXTERN_C const CHAR gc_szSignature[] = "HTTPXPC";
  19. //
  20. // This is declared here because the shared memory library
  21. // now requires any dll or exe using it to define this function.
  22. // However this function is only used for the shared lock cache
  23. // so we do not need to actually implement it for perf counters.
  24. //
  25. namespace IMPLSTUB
  26. {
  27. VOID __fastcall SaveHandle(HANDLE hHandle);
  28. }
  29. VOID __fastcall
  30. IMPLSTUB::SaveHandle(HANDLE h)
  31. {
  32. Assert ( FALSE );
  33. return;
  34. }
  35. // end of hack working around shared lock cache.
  36. //
  37. // The following macros, templates and classes are derived from
  38. // sources in the DAV project.
  39. //
  40. // ========================================================================
  41. //
  42. // TEMPLATE CLASS Singleton
  43. //
  44. // Use this template to implement classes that can only have one instance.
  45. // NOTE: For ref-counted or on-demand global objects, see below
  46. // (RefCountedGlobal and OnDemandGlobal).
  47. //
  48. // The Singleton template provides the following:
  49. //
  50. // o a common memory layout for singleton classes which
  51. // allows template folding to reduce overall code size.
  52. //
  53. // o an instantiation mechanism that verifies (asserts)
  54. // that only instance of your class ever exists.
  55. //
  56. // o asserts to catch any code which attempts to use
  57. // your class when it's not initialized.
  58. //
  59. // To use this template, declare your class like this:
  60. //
  61. // class YourClass : private Singleton<YourClass>
  62. // {
  63. // //
  64. // // Declare Singleton as a friend of YourClass
  65. // // if YourClass's constructor is private (which it
  66. // // should be since YourClass is a singleton and
  67. // // should not be allowed to arbitrarily create
  68. // // instances of it).
  69. // //
  70. // friend class Singleton<YourClass>;
  71. //
  72. // //
  73. // // YourClass private members. Since the 'staticness'
  74. // // of YourClass is provided entirely by this template,
  75. // // you do not need to declare your members as 'static'
  76. // // and you should use standard Hungarian class member
  77. // // naming conventions (e.g. m_dwShoeSize).
  78. // //
  79. // [...]
  80. //
  81. // public:
  82. // //
  83. // // Public declarations for YourClass. Among these should
  84. // // be static functions to init and deinit YourClass which
  85. // // would call CreateInstance() and DestroyInstance()
  86. // // respectively. Or, you could just expose these functions
  87. // // directly to clients of YourClass with using declarations:
  88. // //
  89. // // using Singleton<YourClass>::CreateInstance;
  90. // // using Singleton<YourClass>::DestroyInstance;
  91. // //
  92. // // Similarly, YourClass will probably have additional
  93. // // static methods which access or operate on the
  94. // // singleton instance. These will call Instance()
  95. // // to get at the global instance. Or, though it's
  96. // // not recommended from an encapsulation standpoint,
  97. // // you could expose the global instance directly to
  98. // // clients with:
  99. // //
  100. // // using Singleton<YourClass>::Instance;
  101. // //
  102. // [...]
  103. // };
  104. //
  105. template<class _X>
  106. class Singleton
  107. {
  108. //
  109. // Space for the sole instance
  110. //
  111. static BYTE sm_rgbInstance[];
  112. //
  113. // Pointer to the instance
  114. //
  115. static _X * sm_pInstance;
  116. public:
  117. // STATICS
  118. //
  119. //
  120. // Create the single, global instance of class _X.
  121. //
  122. static _X& CreateInstance()
  123. {
  124. //
  125. // This actually calls Singleton::new()
  126. // (defined below), but calls to new()
  127. // must always be unqualified.
  128. //
  129. return *(new _X());
  130. }
  131. //
  132. // Destroy the single, global instance of class _X.
  133. //
  134. static VOID DestroyInstance()
  135. {
  136. //
  137. // This actually calls Singleton::delete()
  138. // (defined below), but calls to delete()
  139. // must always be unqualified.
  140. //
  141. delete sm_pInstance;
  142. }
  143. //
  144. // Provide access to the single, global instance of class _X.
  145. //
  146. static _X& Instance()
  147. {
  148. Assert( sm_pInstance );
  149. return *sm_pInstance;
  150. }
  151. //
  152. // Singleton operator new and operator delete "allocate"
  153. // space for the object in static memory. These must be
  154. // defined public for syntactic reasons. Do NOT call them
  155. // directly!! Use CreateInstance()/DestroyInstance().
  156. //
  157. static void * operator new(size_t)
  158. {
  159. Assert( !sm_pInstance );
  160. //
  161. // Just return a pointer to the space
  162. // in which to instantiate the object.
  163. //
  164. sm_pInstance = reinterpret_cast<_X *>(sm_rgbInstance);
  165. return sm_pInstance;
  166. }
  167. static void operator delete(void *, size_t)
  168. {
  169. Assert( sm_pInstance );
  170. //
  171. // Since nothing was done to allocate space
  172. // for the instance, we don't do anything
  173. // here to free it.
  174. //
  175. sm_pInstance = NULL;
  176. }
  177. };
  178. //
  179. // Space for the sole instance of class _X
  180. //
  181. template<class _X>
  182. BYTE Singleton<_X>::sm_rgbInstance[sizeof(_X)];
  183. //
  184. // Pointer to the instance
  185. //
  186. template<class _X>
  187. _X * Singleton<_X>::sm_pInstance = NULL;
  188. // ========================================================================
  189. //
  190. // CLASS _Empty
  191. //
  192. // A completely empty, but instantiatable class. Use the _Empty class
  193. // to get around the syntactic inability to instantiate anything of
  194. // type void (or VOID).
  195. //
  196. // In retail builds, _Empty has the same memory footprint and code
  197. // impact as void -- none.
  198. //
  199. // See the RefCountedGlobal template below for a usage example.
  200. //
  201. class _Empty
  202. {
  203. // NOT IMPLEMENTED
  204. //
  205. _Empty( const _Empty& );
  206. _Empty& operator=( const _Empty& );
  207. public:
  208. _Empty() {}
  209. ~_Empty() {}
  210. };
  211. // ========================================================================
  212. //
  213. // TEMPLATE CLASS RefCountedGlobal
  214. //
  215. // Use this template as boilerplate for any class that encapsulates
  216. // a global, refcounted initialization/deinitialization process.
  217. //
  218. // This template maintains proper refcounting and synchronization when
  219. // there are multiple threads trying to initialize and deinitialize
  220. // references at the same time. And it does so without a critical
  221. // section.
  222. //
  223. // To use this template, declare your class like this:
  224. //
  225. // class YourClass : private RefCountedGlobal<YourClass>
  226. // {
  227. // //
  228. // // Declare Singleton and RefCountedGlobal as friends
  229. // // of YourClass so that they can call your private
  230. // // initialization functions.
  231. // //
  232. // friend class Singleton<YourClass>;
  233. // friend class RefCountedGlobal<YourClass>;
  234. //
  235. // //
  236. // // Private declarations for YourClass
  237. // //
  238. // [...]
  239. //
  240. // //
  241. // // Failable initialization function. This function
  242. // // should perform any failable initialization of the
  243. // // instance of YourClass. It should return TRUE
  244. // // if initialization succeeds, and FALSE otherwise.
  245. // // If YourClass does not have any initialization that
  246. // // can fail then you should implement this function inline
  247. // // to just return TRUE.
  248. // //
  249. // BOOL FInit();
  250. //
  251. // public:
  252. // //
  253. // // Public declarations for YourClass. Among these should
  254. // // be static functions to init and deinit YourClass. These
  255. // // functions would call DwInitRef() and DeinitRef() respectively.
  256. // // Or, you could just expose DwInitRef() and DeinitRef()
  257. // // directly to clients of YourClass with using declarations:
  258. // //
  259. // // using RefCountedGlobal<YourClass>::DwInitRef;
  260. // // using RefCountedGlobal<YourClass>::DeinitRef;
  261. // //
  262. // [...]
  263. // };
  264. //
  265. // If YourClass::FInit() succeeds (returns TRUE), then DwInitRef()
  266. // returns the new refcount. If YourClass::FInit() fails (returns
  267. // FALSE), then DwInitRef() returns 0.
  268. //
  269. // See \cal\src\inc\memx.h for sample usage.
  270. //
  271. // If YourClass::FInit() requires initialization parameters, you can
  272. // still use the RefCountedGlobal template. You just need to provide
  273. // your parameter type in the template instantiation and declare your
  274. // FInit() to take a const reference to a parameter of that type:
  275. //
  276. // class YourClass : private RefCountedGlobal<YourClass, YourParameterType>
  277. // {
  278. // //
  279. // // Declare Singleton and RefCountedGlobal as friends
  280. // // of YourClass so that htey can call your private
  281. // // initialization functions.
  282. // //
  283. // // Note the added parameter type to the RefCountedGlobal
  284. // // declaration.
  285. // //
  286. // friend class Singleton<YourClass>;
  287. // friend class RefCountedGlobal<YourClass, YourParameterType>;
  288. //
  289. // //
  290. // // Private declarations for YourClass
  291. // //
  292. // [...]
  293. //
  294. // //
  295. // // Failable initialization function. This function
  296. // // now takes a const ref to the initialization parameters.
  297. // //
  298. // BOOL FInit( const YourParameterType& initParam );
  299. //
  300. // public:
  301. // //
  302. // // Public declarations for YourClass
  303. // //
  304. // [...]
  305. // };
  306. //
  307. // See \cal\src\httpext\entry.cpp for an example of this usage.
  308. //
  309. template<class _X, class _ParmType = _Empty>
  310. class RefCountedGlobal : private Singleton<_X>
  311. {
  312. //
  313. // The object's reference count.
  314. //
  315. static LONG sm_lcRef;
  316. //
  317. // Set of states which describe the object's state
  318. // of initialization. The object's state is
  319. // STATE_UNKNOWN while it is being initialized or
  320. // deinitialized.
  321. //
  322. enum
  323. {
  324. STATE_UNINITIALIZED,
  325. STATE_INITIALIZED,
  326. STATE_UNKNOWN
  327. };
  328. static LONG sm_lState;
  329. //
  330. // Member template that generates an appropriately-typed,
  331. // (inline) function that calls _X::FInit with initialization
  332. // parameters.
  333. //
  334. template<class _P> static BOOL
  335. FInit( const _P& parms ) { return Instance().FInit( parms ); }
  336. //
  337. // Specialization of the above member template for
  338. // the _Empty parameter type, which calls _X::FInit
  339. // without initialization parameters.
  340. //
  341. static BOOL FInit( const _Empty& ) { return Instance().FInit(); }
  342. protected:
  343. //
  344. // Expose access to the single instance of class _X
  345. //
  346. using Singleton<_X>::Instance;
  347. //
  348. // Expose operator new and operator delete from
  349. // the Singleton template so that they will be
  350. // used rather than the default new and delete
  351. // to "allocate" space for the instance of class _X.
  352. //
  353. using Singleton<_X>::operator new;
  354. using Singleton<_X>::operator delete;
  355. static BOOL FInitialized()
  356. {
  357. return sm_lState == STATE_INITIALIZED;
  358. }
  359. static LONG CRef()
  360. {
  361. return sm_lcRef;
  362. }
  363. public:
  364. static DWORD DwInitRef( const _ParmType& parms )
  365. {
  366. LONG lcRef;
  367. //
  368. // Assert the invariant condition that we never have a
  369. // reference without the state being initialized.
  370. //
  371. Assert( sm_lState != STATE_INITIALIZED || sm_lcRef >= 1 );
  372. //
  373. // Add the reference for the instance we're about
  374. // to initialize. Doing this now simplifies the
  375. // code below at the expense of having to decrement
  376. // if first time initialization (FInit()) fails.
  377. // The only thing critical to the design is that
  378. // at any point, when sm_lState is STATE_INITIALIZED,
  379. // sm_lcRef is at least 1.
  380. //
  381. lcRef = InterlockedIncrement( &sm_lcRef );
  382. Assert( lcRef > 0 );
  383. //
  384. // Don't proceed until the object is initialized.
  385. //
  386. while ( sm_lState != STATE_INITIALIZED )
  387. {
  388. //
  389. // Simultaneously check whether initialization has
  390. // started and, if it has not, start it.
  391. //
  392. LONG lStatePrev = InterlockedCompareExchange(
  393. &sm_lState,
  394. STATE_UNKNOWN,
  395. STATE_UNINITIALIZED );
  396. //
  397. // If we're starting first time initialization,
  398. // then create and initialize the sole instance.
  399. //
  400. if ( lStatePrev == STATE_UNINITIALIZED )
  401. {
  402. CreateInstance();
  403. // This calls our private member template FInit()
  404. // (declared above), which in turn calls _X::Finit()
  405. // with the appropriate parameters.
  406. //
  407. if ( FInit( parms ) )
  408. {
  409. sm_lState = STATE_INITIALIZED;
  410. break;
  411. }
  412. // We failed to init.
  413. // Tear down now.
  414. //
  415. Assert( lcRef == 1 );
  416. Assert( sm_lState == STATE_UNKNOWN );
  417. // Let go of our ref on the object.
  418. // Destroy the object.
  419. // And LAST, set the state to UNINITIALIZED.
  420. // NOTE: This will let the next caller through the
  421. // InterlockedCompare above.
  422. //
  423. InterlockedDecrement( &sm_lcRef );
  424. DestroyInstance();
  425. sm_lState = STATE_UNINITIALIZED;
  426. return 0;
  427. }
  428. //
  429. // If first time initialization is in progress on
  430. // another thread, then get out of the way so
  431. // it can finish.
  432. //
  433. //$OPT We should probably spin rather than Sleep()
  434. //$OPT on multi-proc machines on the assumption that
  435. //$OPT we only get here on a processor other than
  436. //$OPT the one which is doing the initialization
  437. //$OPT and we don't want to invite a task switch
  438. //$OPT by calling Sleep() while we are waiting
  439. //$OPT for initialization to complete.
  440. //
  441. if ( lStatePrev == STATE_UNKNOWN )
  442. Sleep(0);
  443. }
  444. //
  445. // At this point, there must be at least
  446. // one initialized reference.
  447. //
  448. Assert( sm_lState == STATE_INITIALIZED );
  449. Assert( sm_lcRef > 0 );
  450. return static_cast<DWORD>(lcRef);
  451. }
  452. static VOID DeinitRef()
  453. {
  454. //
  455. // At this point, there must be at least
  456. // one initialized reference.
  457. //
  458. Assert( sm_lState == STATE_INITIALIZED );
  459. Assert( sm_lcRef > 0 );
  460. //
  461. // Remove that reference. If it is the last
  462. // then deinit the object.
  463. //
  464. if ( 0 == InterlockedDecrement( &sm_lcRef ) )
  465. {
  466. //
  467. // After releasing the last reference, declare that
  468. // the object is in an unknown state. This prevents
  469. // other threads trying to re-initialize the object
  470. // from proceeding until we're done.
  471. //
  472. sm_lState = STATE_UNKNOWN;
  473. //
  474. // There is a tiny window between decrementing the
  475. // refcount and changing the state where another
  476. // initialization could have come through. Test this
  477. // by rechecking the refcount.
  478. //
  479. if ( 0 == sm_lcRef )
  480. {
  481. //
  482. // If the refcount is still zero, then no
  483. // initializations happened before we changed
  484. // states. At this point, if an initialization
  485. // starts, it will block until we change state,
  486. // so it is safe to actually destroy the instance.
  487. //
  488. DestroyInstance();
  489. //
  490. // Once the object has been deinitialized, update
  491. // the state information. This unblocks any
  492. // initializations waiting to happen.
  493. //
  494. sm_lState = STATE_UNINITIALIZED;
  495. }
  496. else // refcount is now non-zero
  497. {
  498. //
  499. // If the refcount is no longer zero, then an
  500. // initialization happened between decrementing
  501. // the refcount above and entering the unknown
  502. // state. When that happens, DO NOT deinit --
  503. // there is now another valid reference somewhere.
  504. // Instead, just restore the object's state to let
  505. // other references proceed.
  506. //
  507. sm_lState = STATE_INITIALIZED;
  508. }
  509. }
  510. //
  511. // Assert the invariant condition that we never have a
  512. // reference without the state being initialized.
  513. //
  514. Assert( sm_lState != STATE_INITIALIZED || sm_lcRef >= 1 );
  515. }
  516. // This provides a no-parameter version of DwInitRef
  517. // for clients that do not need any parameters in FInit().
  518. //
  519. static DWORD DwInitRef()
  520. {
  521. _Empty e;
  522. return DwInitRef( e );
  523. }
  524. };
  525. template<class _X, class _ParmType>
  526. LONG RefCountedGlobal<_X, _ParmType>::sm_lcRef = 0;
  527. template<class _X, class _ParmType>
  528. LONG RefCountedGlobal<_X, _ParmType>::sm_lState = STATE_UNINITIALIZED;
  529. // ========================================================================
  530. // SHARED MEMORY HANDLES
  531. //
  532. // They are always defined as 32 bit values
  533. //
  534. #ifdef _WIN64
  535. typedef VOID * __ptr32 SHMEMHANDLE;
  536. #else
  537. typedef HANDLE SHMEMHANDLE;
  538. #endif
  539. // ========================================================================
  540. //
  541. // NAMESPACE SMH
  542. //
  543. // Differentiates the shared memory heap allocation functions
  544. // from all of the other various heap allocation functions
  545. // in existence.
  546. //
  547. // Yes, this could have been done with a prefix just as easily....
  548. //
  549. namespace SMH
  550. {
  551. BOOL __fastcall FInitialize( IN LPCWSTR pwszInstanceName );
  552. VOID __fastcall Deinitialize();
  553. PVOID __fastcall PvAlloc( IN DWORD cbData, OUT SHMEMHANDLE * phsmba );
  554. VOID __fastcall Free( IN SHMEMHANDLE hsmba );
  555. PVOID __fastcall PvFromSMBA( IN SHMEMHANDLE hsmba );
  556. };
  557. // ========================================================================
  558. //
  559. // CLASS CSmhInit
  560. //
  561. // Initializer for shared memory heap. Any class containing member objects
  562. // that reside on the shared memory heap should also include an instance
  563. // of this class as a member BEFORE the others to ensure that they are
  564. // properly destroyed before the heap is deinitialized.
  565. //
  566. class CSmhInit
  567. {
  568. // NOT IMPLEMENTED
  569. //
  570. CSmhInit& operator=( const CSmhInit& );
  571. CSmhInit( const CSmhInit& );
  572. public:
  573. CSmhInit()
  574. {
  575. }
  576. BOOL FInitialize( LPCWSTR lpwszSignature )
  577. {
  578. #ifdef COMPILE_WITHOUT_DAV
  579. return FALSE;
  580. #else
  581. return SMH::FInitialize( lpwszSignature );
  582. #endif
  583. }
  584. ~CSmhInit()
  585. {
  586. #ifdef COMPILE_WITHOUT_DAV
  587. // do nothing
  588. #else
  589. SMH::Deinitialize();
  590. #endif
  591. }
  592. };
  593. // ========================================================================
  594. //
  595. // TEMPLATE CLASS auto_ptr
  596. //
  597. // Stripped down auto_ptr class based on the C++ STL standard one
  598. //
  599. template<class X>
  600. class auto_ptr
  601. {
  602. mutable X * owner;
  603. X * px;
  604. public:
  605. explicit auto_ptr(X* p=0) : owner(p), px(p) {}
  606. auto_ptr(const auto_ptr<X>& r) : owner(r.owner), px(r.relinquish()) {}
  607. auto_ptr& operator=(const auto_ptr<X>& r)
  608. {
  609. if ((void*)&r != (void*)this)
  610. {
  611. delete owner;
  612. owner = r.owner;
  613. px = r.relinquish();
  614. }
  615. return *this;
  616. }
  617. // NOTE: This equals operator is meant to be used to load a
  618. // new pointer (not yet held in any auto-ptr anywhere) into this object.
  619. auto_ptr& operator=(X* p)
  620. {
  621. Assert(!owner); // Scream on overwrite of good data.
  622. owner = p;
  623. px = p;
  624. return *this;
  625. }
  626. ~auto_ptr() { delete owner; }
  627. bool operator!()const { return (px == NULL); }
  628. operator X*() const { return px; }
  629. X& operator*() const { return *px; }
  630. X* operator->() const { return px; }
  631. X* get() const { return px; }
  632. X* relinquish() const { owner = 0; return px; }
  633. void clear()
  634. {
  635. if (owner)
  636. delete owner;
  637. owner = 0;
  638. px = 0;
  639. }
  640. };
  641. //
  642. // From here down implements the performance monitor for HTTPEXT and
  643. // the functionality necessary to merge perf counters from HTTPEXT
  644. // into the Web Service object defined by W3CTRS.
  645. //
  646. //
  647. // The first flag says whether the CW3Monitor instance has been created.
  648. // The second flag says whether it has been initialized.
  649. // Since the CW3Monitor is created on-demand by the first call to
  650. // W3MergeDavPerformanceData(), these flags keep us from continually
  651. // retrying initialization after it fails the first time.
  652. //
  653. BOOL g_fCreatedMonitor = FALSE;
  654. BOOL g_fInitializedMonitor = FALSE;
  655. // ========================================================================
  656. //
  657. // CLASS CW3Monitor
  658. //
  659. class CW3Monitor : private Singleton<CW3Monitor>
  660. {
  661. //
  662. // Friend declaration required by Singleton template
  663. //
  664. friend class Singleton<CW3Monitor>;
  665. //
  666. // Hint about the size of the buffer to use for perf data coming back
  667. // from HTTPEXT. The buffer needs to be about 48K per vroot. The
  668. // initial guess is 48K (one vroot), and scales up geometrically as
  669. // necessary.
  670. //
  671. DWORD m_cbDavDataAlloc;
  672. //
  673. // Shared memory heap initialization. Declare before any member
  674. // variables which use the shared memory heap to ensure proper
  675. // order of destruction.
  676. //
  677. CSmhInit m_smh;
  678. //
  679. // Perf counter data
  680. //
  681. auto_ptr<ICounterData> m_pCounterData;
  682. // CREATORS
  683. //
  684. CW3Monitor() :
  685. m_cbDavDataAlloc(48 * 1024)
  686. {
  687. }
  688. BOOL FInitialize();
  689. // ACCESSORS
  690. //
  691. DWORD DwCollectPerformanceData( LPBYTE lpbPerfData,
  692. LPDWORD lpdwcbPerfData )
  693. {
  694. DWORD dwcObjectTypes;
  695. return m_pCounterData->DwCollectData( NULL, // Always query all data
  696. 0, // Use 0-relative indices
  697. reinterpret_cast<LPVOID *>(&lpbPerfData),
  698. lpdwcbPerfData,
  699. &dwcObjectTypes );
  700. }
  701. // NOT IMPLEMENTED
  702. //
  703. CW3Monitor& operator=( const CW3Monitor& );
  704. CW3Monitor( const CW3Monitor& );
  705. public:
  706. static BOOL W3MergeDavPerformanceData( DWORD dwServerId, W3_STATISTICS_1 * pW3Stats );
  707. static VOID W3CloseDavPerformanceData()
  708. {
  709. DestroyInstance();
  710. g_fCreatedMonitor = FALSE;
  711. }
  712. };
  713. // ------------------------------------------------------------------------
  714. //
  715. // CW3Monitor::FInitialize()
  716. //
  717. BOOL
  718. CW3Monitor::FInitialize()
  719. {
  720. //
  721. // Initialize the shared memory heap
  722. //
  723. if ( !m_smh.FInitialize( gc_wszSignature ) )
  724. {
  725. DWORD dwResult = GetLastError();
  726. DebugTrace( "CW3Monitor::FInitialize() - Error initializing shared memory heap %d\n", dwResult );
  727. return FALSE;
  728. }
  729. //
  730. // Bind to the counter data
  731. //
  732. #ifdef COMPILE_WITHOUT_DAV
  733. #else
  734. m_pCounterData = NewCounterMonitor( gc_wszSignature );
  735. if ( !m_pCounterData.get() )
  736. {
  737. DWORD dwResult = GetLastError();
  738. DebugTrace( "CW3Monitor::FInitialize() - Error binding to counter data %d\n", dwResult );
  739. return FALSE;
  740. }
  741. #endif
  742. return TRUE;
  743. }
  744. // ------------------------------------------------------------------------
  745. //
  746. // CW3Monitor::W3MergeDavPerformanceData()
  747. //
  748. BOOL
  749. CW3Monitor::W3MergeDavPerformanceData( DWORD dwServerId, W3_STATISTICS_1 * pW3Stats )
  750. {
  751. BYTE * lpbDavData = NULL;
  752. PERF_OBJECT_TYPE * ppot = NULL;
  753. PERF_COUNTER_DEFINITION * rgpcd = NULL;
  754. DWORD dwibServerId = 0;
  755. PERF_INSTANCE_DEFINITION * ppid = NULL;
  756. PERF_COUNTER_BLOCK * ppcb;
  757. LONG lcInstances;
  758. DWORD iCtr;
  759. BOOL fRet = FALSE;
  760. //
  761. // Create the monitor on demand
  762. //
  763. if ( !g_fCreatedMonitor )
  764. {
  765. g_fInitializedMonitor = CreateInstance().FInitialize();
  766. g_fCreatedMonitor = TRUE;
  767. }
  768. //
  769. // If we failed to init the monitor, then we can't get any
  770. // performance data. Since we can't fail this call, just leave
  771. // the existing statistics alone.
  772. //
  773. if ( !g_fInitializedMonitor )
  774. goto ret;
  775. //
  776. // From here out we always return TRUE
  777. //
  778. fRet = TRUE;
  779. //
  780. // Try collecting the data. If our buffer is too small, double
  781. // its size repeatedly until it's big enough. The initial guess
  782. // should be large enough to succeed most of the time.
  783. //
  784. for ( ;; )
  785. {
  786. DWORD cbDavDataAlloc;
  787. DWORD cbDavData;
  788. DWORD dwCollectResult;
  789. // If we have a buffer from a previous trip around the loop
  790. // then free it.
  791. //
  792. if (lpbDavData)
  793. delete [] lpbDavData;
  794. cbDavDataAlloc = Instance().m_cbDavDataAlloc;
  795. cbDavData = cbDavDataAlloc;
  796. lpbDavData = new BYTE[cbDavData];
  797. if (NULL == lpbDavData)
  798. {
  799. DebugTrace( "W3MergeDavPerformanceData() - OOM allocating buffer for DAV perf data\n" );
  800. goto ret;
  801. }
  802. dwCollectResult = Instance().
  803. DwCollectPerformanceData( lpbDavData,
  804. &cbDavData );
  805. if ( ERROR_SUCCESS == dwCollectResult )
  806. {
  807. if ( 0 != cbDavData )
  808. {
  809. break;
  810. }
  811. else
  812. {
  813. DebugTrace( "W3MergeDavPerformanceData() - No instances from which to collect data\n" );
  814. goto ret;
  815. }
  816. }
  817. if ( ERROR_MORE_DATA != dwCollectResult )
  818. {
  819. DebugTrace( "W3MergeDavPerformanceData() - Error collecting DAV perf data (%d)\n", dwCollectResult );
  820. goto ret;
  821. }
  822. Instance().m_cbDavDataAlloc = 2 * cbDavDataAlloc;
  823. }
  824. //
  825. // Locate the HTTPEXT perf object (should be the first
  826. // thing returned) and make sure it looks reasonable.
  827. //
  828. ppot = reinterpret_cast<PERF_OBJECT_TYPE *>( lpbDavData );
  829. if ( ppot->NumCounters < 1 )
  830. {
  831. DebugTrace( "W3MergeDavPerformanceData() - NumCounters < 1?" );
  832. goto ret;
  833. }
  834. if ( ppot->NumInstances < 1 )
  835. {
  836. DebugTrace( "W3MergeDavPerformanceData() - NumInstances < 1?" );
  837. goto ret;
  838. }
  839. //
  840. // Locate the HTTPEXT counter definitions.
  841. //
  842. rgpcd = reinterpret_cast<PERF_COUNTER_DEFINITION *>(
  843. reinterpret_cast<LPBYTE>(ppot) + ppot->HeaderLength );
  844. //
  845. // Locate the server ID counter. This counter tells us what
  846. // instance of the W3Ctrs data to merge into, so bail if we can't
  847. // find it or if it looks wrong.
  848. //
  849. for ( iCtr = 0; iCtr < ppot->NumCounters; iCtr++ )
  850. {
  851. if ( rgpcd[iCtr].CounterNameTitleIndex == HTTPEXT_COUNTER_SERVER_ID )
  852. {
  853. if ( rgpcd[iCtr].CounterSize == sizeof(DWORD) &&
  854. rgpcd[iCtr].CounterType == (PERF_DISPLAY_NOSHOW |
  855. PERF_SIZE_DWORD |
  856. PERF_TYPE_NUMBER) )
  857. {
  858. dwibServerId = rgpcd[iCtr].CounterOffset;
  859. break;
  860. }
  861. else
  862. {
  863. DebugTrace( "W3MergePerformanceData() - Server ID counter doesn't look right. Bailing...\n" );
  864. goto ret;
  865. }
  866. }
  867. }
  868. if ( !dwibServerId )
  869. {
  870. DebugTrace( "W3MergePerformanceData() - Couldn't find server ID counter. Bailing...\n" );
  871. goto ret;
  872. }
  873. //
  874. // Now go through each instance of the HTTPEXT counters and merge the data
  875. // from that instance into the correct W3Ctrs counter instance according
  876. // to server ID.
  877. //
  878. ppid = reinterpret_cast<PERF_INSTANCE_DEFINITION *>(
  879. reinterpret_cast<LPBYTE>(ppot) + ppot->DefinitionLength );
  880. for ( lcInstances = ppot->NumInstances;
  881. lcInstances-- > 0;
  882. ppid = reinterpret_cast<PERF_INSTANCE_DEFINITION *>(
  883. reinterpret_cast<LPBYTE>(ppcb) + ppcb->ByteLength ) )
  884. {
  885. ppcb = reinterpret_cast<PERF_COUNTER_BLOCK *>(
  886. reinterpret_cast<LPBYTE>(ppid) + ppid->ByteLength );
  887. //
  888. // Get the server ID of this instance.
  889. //
  890. DWORD dwServerIdInstance =
  891. *reinterpret_cast<LPDWORD>(
  892. reinterpret_cast<LPBYTE>(ppcb) + dwibServerId);
  893. //
  894. // If the server ID of this instance isn't the one
  895. // we want then keep looking.
  896. //
  897. if ( dwServerIdInstance != dwServerId )
  898. continue;
  899. //
  900. // The server IDs match, so sum in the info for this instance.
  901. // NOTE: Since each vroot has its own instance, there may be
  902. // multiple instances with the same server ID. Sum them all.
  903. //
  904. // Go through all the counters in the HTTPEXT instance
  905. // and update the W3 statistics data.
  906. //
  907. for ( DWORD iCounter = 0;
  908. iCounter < ppot->NumCounters;
  909. iCounter++ )
  910. {
  911. PERF_COUNTER_DEFINITION * ppcd = &rgpcd[iCounter];
  912. switch ( ppcd->CounterNameTitleIndex )
  913. {
  914. case HTTPEXT_COUNTER_TOTAL_GET_REQUESTS:
  915. case HTTPEXT_COUNTER_TOTAL_HEAD_REQUESTS:
  916. case HTTPEXT_COUNTER_TOTAL_POST_REQUESTS:
  917. case HTTPEXT_COUNTER_TOTAL_DELETE_REQUESTS:
  918. case HTTPEXT_COUNTER_TOTAL_OTHER_REQUESTS:
  919. {
  920. //
  921. // These values are already recorded
  922. // in the statistics, so don't do anything
  923. // more with them here.
  924. //
  925. break;
  926. }
  927. case HTTPEXT_COUNTER_TOTAL_PUT_REQUESTS:
  928. {
  929. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  930. ppcd->CounterSize == sizeof(DWORD) )
  931. {
  932. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  933. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  934. pW3Stats->TotalFilesReceived += dwValue;
  935. }
  936. break;
  937. }
  938. case HTTPEXT_COUNTER_TOTAL_OPTIONS_REQUESTS:
  939. {
  940. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  941. ppcd->CounterSize == sizeof(DWORD) )
  942. {
  943. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  944. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  945. pW3Stats->TotalOptions += dwValue;
  946. pW3Stats->TotalOthers -= dwValue;
  947. }
  948. break;
  949. }
  950. case HTTPEXT_COUNTER_TOTAL_COPY_REQUESTS:
  951. {
  952. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  953. ppcd->CounterSize == sizeof(DWORD) )
  954. {
  955. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  956. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  957. pW3Stats->TotalCopy += dwValue;
  958. pW3Stats->TotalOthers -= dwValue;
  959. }
  960. break;
  961. }
  962. case HTTPEXT_COUNTER_TOTAL_MOVE_REQUESTS:
  963. {
  964. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  965. ppcd->CounterSize == sizeof(DWORD) )
  966. {
  967. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  968. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  969. pW3Stats->TotalMove += dwValue;
  970. pW3Stats->TotalOthers -= dwValue;
  971. }
  972. break;
  973. }
  974. case HTTPEXT_COUNTER_TOTAL_MKCOL_REQUESTS:
  975. {
  976. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  977. ppcd->CounterSize == sizeof(DWORD) )
  978. {
  979. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  980. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  981. pW3Stats->TotalMkcol += dwValue;
  982. pW3Stats->TotalOthers -= dwValue;
  983. }
  984. break;
  985. }
  986. case HTTPEXT_COUNTER_TOTAL_PROPFIND_REQUESTS:
  987. {
  988. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  989. ppcd->CounterSize == sizeof(DWORD) )
  990. {
  991. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  992. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  993. pW3Stats->TotalPropfind += dwValue;
  994. pW3Stats->TotalOthers -= dwValue;
  995. }
  996. break;
  997. }
  998. case HTTPEXT_COUNTER_TOTAL_PROPPATCH_REQUESTS:
  999. {
  1000. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  1001. ppcd->CounterSize == sizeof(DWORD) )
  1002. {
  1003. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  1004. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  1005. pW3Stats->TotalProppatch += dwValue;
  1006. pW3Stats->TotalOthers -= dwValue;
  1007. }
  1008. break;
  1009. }
  1010. case HTTPEXT_COUNTER_TOTAL_SEARCH_REQUESTS:
  1011. {
  1012. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  1013. ppcd->CounterSize == sizeof(DWORD) )
  1014. {
  1015. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  1016. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  1017. pW3Stats->TotalSearch += dwValue;
  1018. pW3Stats->TotalOthers -= dwValue;
  1019. }
  1020. break;
  1021. }
  1022. case HTTPEXT_COUNTER_TOTAL_LOCK_REQUESTS:
  1023. {
  1024. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  1025. ppcd->CounterSize == sizeof(DWORD) )
  1026. {
  1027. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  1028. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  1029. pW3Stats->TotalLock += dwValue;
  1030. pW3Stats->TotalOthers -= dwValue;
  1031. }
  1032. break;
  1033. }
  1034. case HTTPEXT_COUNTER_TOTAL_UNLOCK_REQUESTS:
  1035. {
  1036. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  1037. ppcd->CounterSize == sizeof(DWORD) )
  1038. {
  1039. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  1040. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  1041. pW3Stats->TotalUnlock += dwValue;
  1042. pW3Stats->TotalOthers -= dwValue;
  1043. }
  1044. break;
  1045. }
  1046. case HTTPEXT_COUNTER_TOTAL_404_RESPONSES:
  1047. {
  1048. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  1049. ppcd->CounterSize == sizeof(DWORD) )
  1050. {
  1051. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  1052. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  1053. pW3Stats->TotalNotFoundErrors += dwValue;
  1054. }
  1055. break;
  1056. }
  1057. case HTTPEXT_COUNTER_TOTAL_423_RESPONSES:
  1058. {
  1059. if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
  1060. ppcd->CounterSize == sizeof(DWORD) )
  1061. {
  1062. DWORD dwValue = *reinterpret_cast<LPDWORD>(
  1063. reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
  1064. pW3Stats->TotalLockedErrors += dwValue;
  1065. }
  1066. break;
  1067. }
  1068. default:
  1069. {
  1070. //
  1071. // We either don't care about or don't understand
  1072. // other counters, so skip them.
  1073. //
  1074. break;
  1075. }
  1076. }
  1077. }
  1078. }
  1079. ret:
  1080. if (lpbDavData)
  1081. delete [] lpbDavData;
  1082. return fRet;
  1083. }
  1084. // ========================================================================
  1085. //
  1086. // CLASS CW3MonitorInit
  1087. //
  1088. // Refcounted global initialization class that controls the lifetime of
  1089. // the singleton CW3Monitor instance. Calls to collect performance data
  1090. // are done in the scope of a reference to this class so that the server
  1091. // can be taken down on one thread while another thread is in the middle
  1092. // of -- or just beginning to -- collect data. Whichever thread releases
  1093. // the last reference to this class will be the one to close the counters.
  1094. //
  1095. class CW3MonitorInit : private RefCountedGlobal<CW3MonitorInit>
  1096. {
  1097. //
  1098. // Friend declarations required by RefCountedGlobal template
  1099. //
  1100. friend class Singleton<CW3MonitorInit>;
  1101. friend class RefCountedGlobal<CW3MonitorInit>;
  1102. // CREATORS
  1103. //
  1104. // Declared private to ensure that arbitrary instances
  1105. // of this class cannot be created. The Singleton
  1106. // template (declared as a friend above) controls
  1107. // the sole instance of this class.
  1108. //
  1109. CW3MonitorInit()
  1110. {
  1111. }
  1112. BOOL FInit()
  1113. {
  1114. return TRUE;
  1115. }
  1116. ~CW3MonitorInit()
  1117. {
  1118. CW3Monitor::W3CloseDavPerformanceData();
  1119. }
  1120. // NOT IMPLEMENTED
  1121. //
  1122. CW3MonitorInit( const CW3MonitorInit& );
  1123. CW3MonitorInit& operator=( const CW3MonitorInit& );
  1124. public:
  1125. using RefCountedGlobal<CW3MonitorInit>::DwInitRef;
  1126. using RefCountedGlobal<CW3MonitorInit>::DeinitRef;
  1127. };
  1128. // ========================================================================
  1129. //
  1130. // PUBLIC INTERFACE
  1131. //
  1132. // ------------------------------------------------------------------------
  1133. //
  1134. // W3MergeDavPerformanceData()
  1135. //
  1136. EXTERN_C BOOL __fastcall
  1137. W3MergeDavPerformanceData( DWORD dwServerId, W3_STATISTICS_1 * pW3Stats )
  1138. {
  1139. BOOL fResult;
  1140. CW3MonitorInit::DwInitRef();
  1141. fResult = CW3Monitor::W3MergeDavPerformanceData( dwServerId, pW3Stats );
  1142. CW3MonitorInit::DeinitRef();
  1143. return fResult;
  1144. }
  1145. // ------------------------------------------------------------------------
  1146. //
  1147. // W3OpenDavPerformanceData()
  1148. //
  1149. EXTERN_C VOID __fastcall
  1150. W3OpenDavPerformanceData()
  1151. {
  1152. CW3MonitorInit::DwInitRef();
  1153. }
  1154. // ------------------------------------------------------------------------
  1155. //
  1156. // W3CloseDavPerformanceData()
  1157. //
  1158. EXTERN_C VOID __fastcall
  1159. W3CloseDavPerformanceData()
  1160. {
  1161. CW3MonitorInit::DeinitRef();
  1162. }