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.

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