windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/w3/server/httpxpc.cxx
2020-09-26 16:20:57 +08:00

1344 lines
32 KiB
C++

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// HTTPXPC.CXX
//
// Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
//
// Monitor-side for W3 integration.
//
#include "w3p.hxx" // W3SVC Precompiled header
#include <windows.h>
#include <winperf.h>
#include "pclib.hxx"
#include "httpxctr.hxx" // Perf counter title index #defines
#include "caldbg.h" // For DebugTrace()/Assert()
EXTERN_C const WCHAR gc_wszSignature[] = L"HTTPEXT";
EXTERN_C const CHAR gc_szDbgIni[] = "HTTPXPC.INI";
EXTERN_C const CHAR gc_szSignature[] = "HTTPXPC";
//
// This is declared here because the shared memory library
// now requires any dll or exe using it to define this function.
// However this function is only used for the shared lock cache
// so we do not need to actually implement it for perf counters.
//
namespace IMPLSTUB
{
VOID __fastcall SaveHandle(HANDLE hHandle);
}
VOID __fastcall
IMPLSTUB::SaveHandle(HANDLE h)
{
Assert ( FALSE );
return;
}
// end of hack working around shared lock cache.
//
// The following macros, templates and classes are derived from
// sources in the DAV project.
//
// ========================================================================
//
// TEMPLATE CLASS Singleton
//
// Use this template to implement classes that can only have one instance.
// NOTE: For ref-counted or on-demand global objects, see below
// (RefCountedGlobal and OnDemandGlobal).
//
// The Singleton template provides the following:
//
// o a common memory layout for singleton classes which
// allows template folding to reduce overall code size.
//
// o an instantiation mechanism that verifies (asserts)
// that only instance of your class ever exists.
//
// o asserts to catch any code which attempts to use
// your class when it's not initialized.
//
// To use this template, declare your class like this:
//
// class YourClass : private Singleton<YourClass>
// {
// //
// // Declare Singleton as a friend of YourClass
// // if YourClass's constructor is private (which it
// // should be since YourClass is a singleton and
// // should not be allowed to arbitrarily create
// // instances of it).
// //
// friend class Singleton<YourClass>;
//
// //
// // YourClass private members. Since the 'staticness'
// // of YourClass is provided entirely by this template,
// // you do not need to declare your members as 'static'
// // and you should use standard Hungarian class member
// // naming conventions (e.g. m_dwShoeSize).
// //
// [...]
//
// public:
// //
// // Public declarations for YourClass. Among these should
// // be static functions to init and deinit YourClass which
// // would call CreateInstance() and DestroyInstance()
// // respectively. Or, you could just expose these functions
// // directly to clients of YourClass with using declarations:
// //
// // using Singleton<YourClass>::CreateInstance;
// // using Singleton<YourClass>::DestroyInstance;
// //
// // Similarly, YourClass will probably have additional
// // static methods which access or operate on the
// // singleton instance. These will call Instance()
// // to get at the global instance. Or, though it's
// // not recommended from an encapsulation standpoint,
// // you could expose the global instance directly to
// // clients with:
// //
// // using Singleton<YourClass>::Instance;
// //
// [...]
// };
//
template<class _X>
class Singleton
{
//
// Space for the sole instance
//
static BYTE sm_rgbInstance[];
//
// Pointer to the instance
//
static _X * sm_pInstance;
public:
// STATICS
//
//
// Create the single, global instance of class _X.
//
static _X& CreateInstance()
{
//
// This actually calls Singleton::new()
// (defined below), but calls to new()
// must always be unqualified.
//
return *(new _X());
}
//
// Destroy the single, global instance of class _X.
//
static VOID DestroyInstance()
{
//
// This actually calls Singleton::delete()
// (defined below), but calls to delete()
// must always be unqualified.
//
delete sm_pInstance;
}
//
// Provide access to the single, global instance of class _X.
//
static _X& Instance()
{
Assert( sm_pInstance );
return *sm_pInstance;
}
//
// Singleton operator new and operator delete "allocate"
// space for the object in static memory. These must be
// defined public for syntactic reasons. Do NOT call them
// directly!! Use CreateInstance()/DestroyInstance().
//
static void * operator new(size_t)
{
Assert( !sm_pInstance );
//
// Just return a pointer to the space
// in which to instantiate the object.
//
sm_pInstance = reinterpret_cast<_X *>(sm_rgbInstance);
return sm_pInstance;
}
static void operator delete(void *, size_t)
{
Assert( sm_pInstance );
//
// Since nothing was done to allocate space
// for the instance, we don't do anything
// here to free it.
//
sm_pInstance = NULL;
}
};
//
// Space for the sole instance of class _X
//
template<class _X>
BYTE Singleton<_X>::sm_rgbInstance[sizeof(_X)];
//
// Pointer to the instance
//
template<class _X>
_X * Singleton<_X>::sm_pInstance = NULL;
// ========================================================================
//
// CLASS _Empty
//
// A completely empty, but instantiatable class. Use the _Empty class
// to get around the syntactic inability to instantiate anything of
// type void (or VOID).
//
// In retail builds, _Empty has the same memory footprint and code
// impact as void -- none.
//
// See the RefCountedGlobal template below for a usage example.
//
class _Empty
{
// NOT IMPLEMENTED
//
_Empty( const _Empty& );
_Empty& operator=( const _Empty& );
public:
_Empty() {}
~_Empty() {}
};
// ========================================================================
//
// TEMPLATE CLASS RefCountedGlobal
//
// Use this template as boilerplate for any class that encapsulates
// a global, refcounted initialization/deinitialization process.
//
// This template maintains proper refcounting and synchronization when
// there are multiple threads trying to initialize and deinitialize
// references at the same time. And it does so without a critical
// section.
//
// To use this template, declare your class like this:
//
// class YourClass : private RefCountedGlobal<YourClass>
// {
// //
// // Declare Singleton and RefCountedGlobal as friends
// // of YourClass so that they can call your private
// // initialization functions.
// //
// friend class Singleton<YourClass>;
// friend class RefCountedGlobal<YourClass>;
//
// //
// // Private declarations for YourClass
// //
// [...]
//
// //
// // Failable initialization function. This function
// // should perform any failable initialization of the
// // instance of YourClass. It should return TRUE
// // if initialization succeeds, and FALSE otherwise.
// // If YourClass does not have any initialization that
// // can fail then you should implement this function inline
// // to just return TRUE.
// //
// BOOL FInit();
//
// public:
// //
// // Public declarations for YourClass. Among these should
// // be static functions to init and deinit YourClass. These
// // functions would call DwInitRef() and DeinitRef() respectively.
// // Or, you could just expose DwInitRef() and DeinitRef()
// // directly to clients of YourClass with using declarations:
// //
// // using RefCountedGlobal<YourClass>::DwInitRef;
// // using RefCountedGlobal<YourClass>::DeinitRef;
// //
// [...]
// };
//
// If YourClass::FInit() succeeds (returns TRUE), then DwInitRef()
// returns the new refcount. If YourClass::FInit() fails (returns
// FALSE), then DwInitRef() returns 0.
//
// See \cal\src\inc\memx.h for sample usage.
//
// If YourClass::FInit() requires initialization parameters, you can
// still use the RefCountedGlobal template. You just need to provide
// your parameter type in the template instantiation and declare your
// FInit() to take a const reference to a parameter of that type:
//
// class YourClass : private RefCountedGlobal<YourClass, YourParameterType>
// {
// //
// // Declare Singleton and RefCountedGlobal as friends
// // of YourClass so that htey can call your private
// // initialization functions.
// //
// // Note the added parameter type to the RefCountedGlobal
// // declaration.
// //
// friend class Singleton<YourClass>;
// friend class RefCountedGlobal<YourClass, YourParameterType>;
//
// //
// // Private declarations for YourClass
// //
// [...]
//
// //
// // Failable initialization function. This function
// // now takes a const ref to the initialization parameters.
// //
// BOOL FInit( const YourParameterType& initParam );
//
// public:
// //
// // Public declarations for YourClass
// //
// [...]
// };
//
// See \cal\src\httpext\entry.cpp for an example of this usage.
//
template<class _X, class _ParmType = _Empty>
class RefCountedGlobal : private Singleton<_X>
{
//
// The object's reference count.
//
static LONG sm_lcRef;
//
// Set of states which describe the object's state
// of initialization. The object's state is
// STATE_UNKNOWN while it is being initialized or
// deinitialized.
//
enum
{
STATE_UNINITIALIZED,
STATE_INITIALIZED,
STATE_UNKNOWN
};
static LONG sm_lState;
//
// Member template that generates an appropriately-typed,
// (inline) function that calls _X::FInit with initialization
// parameters.
//
template<class _P> static BOOL
FInit( const _P& parms ) { return Instance().FInit( parms ); }
//
// Specialization of the above member template for
// the _Empty parameter type, which calls _X::FInit
// without initialization parameters.
//
static BOOL FInit( const _Empty& ) { return Instance().FInit(); }
protected:
//
// Expose access to the single instance of class _X
//
using Singleton<_X>::Instance;
//
// Expose operator new and operator delete from
// the Singleton template so that they will be
// used rather than the default new and delete
// to "allocate" space for the instance of class _X.
//
using Singleton<_X>::operator new;
using Singleton<_X>::operator delete;
static BOOL FInitialized()
{
return sm_lState == STATE_INITIALIZED;
}
static LONG CRef()
{
return sm_lcRef;
}
public:
static DWORD DwInitRef( const _ParmType& parms )
{
LONG lcRef;
//
// Assert the invariant condition that we never have a
// reference without the state being initialized.
//
Assert( sm_lState != STATE_INITIALIZED || sm_lcRef >= 1 );
//
// Add the reference for the instance we're about
// to initialize. Doing this now simplifies the
// code below at the expense of having to decrement
// if first time initialization (FInit()) fails.
// The only thing critical to the design is that
// at any point, when sm_lState is STATE_INITIALIZED,
// sm_lcRef is at least 1.
//
lcRef = InterlockedIncrement( &sm_lcRef );
Assert( lcRef > 0 );
//
// Don't proceed until the object is initialized.
//
while ( sm_lState != STATE_INITIALIZED )
{
//
// Simultaneously check whether initialization has
// started and, if it has not, start it.
//
LONG lStatePrev = InterlockedCompareExchange(
&sm_lState,
STATE_UNKNOWN,
STATE_UNINITIALIZED );
//
// If we're starting first time initialization,
// then create and initialize the sole instance.
//
if ( lStatePrev == STATE_UNINITIALIZED )
{
CreateInstance();
// This calls our private member template FInit()
// (declared above), which in turn calls _X::Finit()
// with the appropriate parameters.
//
if ( FInit( parms ) )
{
sm_lState = STATE_INITIALIZED;
break;
}
// We failed to init.
// Tear down now.
//
Assert( lcRef == 1 );
Assert( sm_lState == STATE_UNKNOWN );
// Let go of our ref on the object.
// Destroy the object.
// And LAST, set the state to UNINITIALIZED.
// NOTE: This will let the next caller through the
// InterlockedCompare above.
//
InterlockedDecrement( &sm_lcRef );
DestroyInstance();
sm_lState = STATE_UNINITIALIZED;
return 0;
}
//
// If first time initialization is in progress on
// another thread, then get out of the way so
// it can finish.
//
//$OPT We should probably spin rather than Sleep()
//$OPT on multi-proc machines on the assumption that
//$OPT we only get here on a processor other than
//$OPT the one which is doing the initialization
//$OPT and we don't want to invite a task switch
//$OPT by calling Sleep() while we are waiting
//$OPT for initialization to complete.
//
if ( lStatePrev == STATE_UNKNOWN )
Sleep(0);
}
//
// At this point, there must be at least
// one initialized reference.
//
Assert( sm_lState == STATE_INITIALIZED );
Assert( sm_lcRef > 0 );
return static_cast<DWORD>(lcRef);
}
static VOID DeinitRef()
{
//
// At this point, there must be at least
// one initialized reference.
//
Assert( sm_lState == STATE_INITIALIZED );
Assert( sm_lcRef > 0 );
//
// Remove that reference. If it is the last
// then deinit the object.
//
if ( 0 == InterlockedDecrement( &sm_lcRef ) )
{
//
// After releasing the last reference, declare that
// the object is in an unknown state. This prevents
// other threads trying to re-initialize the object
// from proceeding until we're done.
//
sm_lState = STATE_UNKNOWN;
//
// There is a tiny window between decrementing the
// refcount and changing the state where another
// initialization could have come through. Test this
// by rechecking the refcount.
//
if ( 0 == sm_lcRef )
{
//
// If the refcount is still zero, then no
// initializations happened before we changed
// states. At this point, if an initialization
// starts, it will block until we change state,
// so it is safe to actually destroy the instance.
//
DestroyInstance();
//
// Once the object has been deinitialized, update
// the state information. This unblocks any
// initializations waiting to happen.
//
sm_lState = STATE_UNINITIALIZED;
}
else // refcount is now non-zero
{
//
// If the refcount is no longer zero, then an
// initialization happened between decrementing
// the refcount above and entering the unknown
// state. When that happens, DO NOT deinit --
// there is now another valid reference somewhere.
// Instead, just restore the object's state to let
// other references proceed.
//
sm_lState = STATE_INITIALIZED;
}
}
//
// Assert the invariant condition that we never have a
// reference without the state being initialized.
//
Assert( sm_lState != STATE_INITIALIZED || sm_lcRef >= 1 );
}
// This provides a no-parameter version of DwInitRef
// for clients that do not need any parameters in FInit().
//
static DWORD DwInitRef()
{
_Empty e;
return DwInitRef( e );
}
};
template<class _X, class _ParmType>
LONG RefCountedGlobal<_X, _ParmType>::sm_lcRef = 0;
template<class _X, class _ParmType>
LONG RefCountedGlobal<_X, _ParmType>::sm_lState = STATE_UNINITIALIZED;
// ========================================================================
// SHARED MEMORY HANDLES
//
// They are always defined as 32 bit values
//
#ifdef _WIN64
typedef VOID * __ptr32 SHMEMHANDLE;
#else
typedef HANDLE SHMEMHANDLE;
#endif
// ========================================================================
//
// NAMESPACE SMH
//
// Differentiates the shared memory heap allocation functions
// from all of the other various heap allocation functions
// in existence.
//
// Yes, this could have been done with a prefix just as easily....
//
namespace SMH
{
BOOL __fastcall FInitialize( IN LPCWSTR pwszInstanceName );
VOID __fastcall Deinitialize();
PVOID __fastcall PvAlloc( IN DWORD cbData, OUT SHMEMHANDLE * phsmba );
VOID __fastcall Free( IN SHMEMHANDLE hsmba );
PVOID __fastcall PvFromSMBA( IN SHMEMHANDLE hsmba );
};
// ========================================================================
//
// CLASS CSmhInit
//
// Initializer for shared memory heap. Any class containing member objects
// that reside on the shared memory heap should also include an instance
// of this class as a member BEFORE the others to ensure that they are
// properly destroyed before the heap is deinitialized.
//
class CSmhInit
{
// NOT IMPLEMENTED
//
CSmhInit& operator=( const CSmhInit& );
CSmhInit( const CSmhInit& );
public:
CSmhInit()
{
}
BOOL FInitialize( LPCWSTR lpwszSignature )
{
#ifdef COMPILE_WITHOUT_DAV
return FALSE;
#else
return SMH::FInitialize( lpwszSignature );
#endif
}
~CSmhInit()
{
#ifdef COMPILE_WITHOUT_DAV
// do nothing
#else
SMH::Deinitialize();
#endif
}
};
// ========================================================================
//
// TEMPLATE CLASS auto_ptr
//
// Stripped down auto_ptr class based on the C++ STL standard one
//
template<class X>
class auto_ptr
{
mutable X * owner;
X * px;
public:
explicit auto_ptr(X* p=0) : owner(p), px(p) {}
auto_ptr(const auto_ptr<X>& r) : owner(r.owner), px(r.relinquish()) {}
auto_ptr& operator=(const auto_ptr<X>& r)
{
if ((void*)&r != (void*)this)
{
delete owner;
owner = r.owner;
px = r.relinquish();
}
return *this;
}
// NOTE: This equals operator is meant to be used to load a
// new pointer (not yet held in any auto-ptr anywhere) into this object.
auto_ptr& operator=(X* p)
{
Assert(!owner); // Scream on overwrite of good data.
owner = p;
px = p;
return *this;
}
~auto_ptr() { delete owner; }
bool operator!()const { return (px == NULL); }
operator X*() const { return px; }
X& operator*() const { return *px; }
X* operator->() const { return px; }
X* get() const { return px; }
X* relinquish() const { owner = 0; return px; }
void clear()
{
if (owner)
delete owner;
owner = 0;
px = 0;
}
};
//
// From here down implements the performance monitor for HTTPEXT and
// the functionality necessary to merge perf counters from HTTPEXT
// into the Web Service object defined by W3CTRS.
//
//
// The first flag says whether the CW3Monitor instance has been created.
// The second flag says whether it has been initialized.
// Since the CW3Monitor is created on-demand by the first call to
// W3MergeDavPerformanceData(), these flags keep us from continually
// retrying initialization after it fails the first time.
//
BOOL g_fCreatedMonitor = FALSE;
BOOL g_fInitializedMonitor = FALSE;
// ========================================================================
//
// CLASS CW3Monitor
//
class CW3Monitor : private Singleton<CW3Monitor>
{
//
// Friend declaration required by Singleton template
//
friend class Singleton<CW3Monitor>;
//
// Hint about the size of the buffer to use for perf data coming back
// from HTTPEXT. The buffer needs to be about 48K per vroot. The
// initial guess is 48K (one vroot), and scales up geometrically as
// necessary.
//
DWORD m_cbDavDataAlloc;
//
// Shared memory heap initialization. Declare before any member
// variables which use the shared memory heap to ensure proper
// order of destruction.
//
CSmhInit m_smh;
//
// Perf counter data
//
auto_ptr<ICounterData> m_pCounterData;
// CREATORS
//
CW3Monitor() :
m_cbDavDataAlloc(48 * 1024)
{
}
BOOL FInitialize();
// ACCESSORS
//
DWORD DwCollectPerformanceData( LPBYTE lpbPerfData,
LPDWORD lpdwcbPerfData )
{
DWORD dwcObjectTypes;
return m_pCounterData->DwCollectData( NULL, // Always query all data
0, // Use 0-relative indices
reinterpret_cast<LPVOID *>(&lpbPerfData),
lpdwcbPerfData,
&dwcObjectTypes );
}
// NOT IMPLEMENTED
//
CW3Monitor& operator=( const CW3Monitor& );
CW3Monitor( const CW3Monitor& );
public:
static BOOL W3MergeDavPerformanceData( DWORD dwServerId, W3_STATISTICS_1 * pW3Stats );
static VOID W3CloseDavPerformanceData()
{
DestroyInstance();
g_fCreatedMonitor = FALSE;
}
};
// ------------------------------------------------------------------------
//
// CW3Monitor::FInitialize()
//
BOOL
CW3Monitor::FInitialize()
{
//
// Initialize the shared memory heap
//
if ( !m_smh.FInitialize( gc_wszSignature ) )
{
DWORD dwResult = GetLastError();
DebugTrace( "CW3Monitor::FInitialize() - Error initializing shared memory heap %d\n", dwResult );
return FALSE;
}
//
// Bind to the counter data
//
#ifdef COMPILE_WITHOUT_DAV
#else
m_pCounterData = NewCounterMonitor( gc_wszSignature );
if ( !m_pCounterData.get() )
{
DWORD dwResult = GetLastError();
DebugTrace( "CW3Monitor::FInitialize() - Error binding to counter data %d\n", dwResult );
return FALSE;
}
#endif
return TRUE;
}
// ------------------------------------------------------------------------
//
// CW3Monitor::W3MergeDavPerformanceData()
//
BOOL
CW3Monitor::W3MergeDavPerformanceData( DWORD dwServerId, W3_STATISTICS_1 * pW3Stats )
{
BYTE * lpbDavData = NULL;
PERF_OBJECT_TYPE * ppot = NULL;
PERF_COUNTER_DEFINITION * rgpcd = NULL;
DWORD dwibServerId = 0;
PERF_INSTANCE_DEFINITION * ppid = NULL;
PERF_COUNTER_BLOCK * ppcb;
LONG lcInstances;
DWORD iCtr;
BOOL fRet = FALSE;
//
// Create the monitor on demand
//
if ( !g_fCreatedMonitor )
{
g_fInitializedMonitor = CreateInstance().FInitialize();
g_fCreatedMonitor = TRUE;
}
//
// If we failed to init the monitor, then we can't get any
// performance data. Since we can't fail this call, just leave
// the existing statistics alone.
//
if ( !g_fInitializedMonitor )
goto ret;
//
// From here out we always return TRUE
//
fRet = TRUE;
//
// Try collecting the data. If our buffer is too small, double
// its size repeatedly until it's big enough. The initial guess
// should be large enough to succeed most of the time.
//
for ( ;; )
{
DWORD cbDavDataAlloc;
DWORD cbDavData;
DWORD dwCollectResult;
// If we have a buffer from a previous trip around the loop
// then free it.
//
if (lpbDavData)
delete [] lpbDavData;
cbDavDataAlloc = Instance().m_cbDavDataAlloc;
cbDavData = cbDavDataAlloc;
lpbDavData = new BYTE[cbDavData];
if (NULL == lpbDavData)
{
DebugTrace( "W3MergeDavPerformanceData() - OOM allocating buffer for DAV perf data\n" );
goto ret;
}
dwCollectResult = Instance().
DwCollectPerformanceData( lpbDavData,
&cbDavData );
if ( ERROR_SUCCESS == dwCollectResult )
{
if ( 0 != cbDavData )
{
break;
}
else
{
DebugTrace( "W3MergeDavPerformanceData() - No instances from which to collect data\n" );
goto ret;
}
}
if ( ERROR_MORE_DATA != dwCollectResult )
{
DebugTrace( "W3MergeDavPerformanceData() - Error collecting DAV perf data (%d)\n", dwCollectResult );
goto ret;
}
Instance().m_cbDavDataAlloc = 2 * cbDavDataAlloc;
}
//
// Locate the HTTPEXT perf object (should be the first
// thing returned) and make sure it looks reasonable.
//
ppot = reinterpret_cast<PERF_OBJECT_TYPE *>( lpbDavData );
if ( ppot->NumCounters < 1 )
{
DebugTrace( "W3MergeDavPerformanceData() - NumCounters < 1?" );
goto ret;
}
if ( ppot->NumInstances < 1 )
{
DebugTrace( "W3MergeDavPerformanceData() - NumInstances < 1?" );
goto ret;
}
//
// Locate the HTTPEXT counter definitions.
//
rgpcd = reinterpret_cast<PERF_COUNTER_DEFINITION *>(
reinterpret_cast<LPBYTE>(ppot) + ppot->HeaderLength );
//
// Locate the server ID counter. This counter tells us what
// instance of the W3Ctrs data to merge into, so bail if we can't
// find it or if it looks wrong.
//
for ( iCtr = 0; iCtr < ppot->NumCounters; iCtr++ )
{
if ( rgpcd[iCtr].CounterNameTitleIndex == HTTPEXT_COUNTER_SERVER_ID )
{
if ( rgpcd[iCtr].CounterSize == sizeof(DWORD) &&
rgpcd[iCtr].CounterType == (PERF_DISPLAY_NOSHOW |
PERF_SIZE_DWORD |
PERF_TYPE_NUMBER) )
{
dwibServerId = rgpcd[iCtr].CounterOffset;
break;
}
else
{
DebugTrace( "W3MergePerformanceData() - Server ID counter doesn't look right. Bailing...\n" );
goto ret;
}
}
}
if ( !dwibServerId )
{
DebugTrace( "W3MergePerformanceData() - Couldn't find server ID counter. Bailing...\n" );
goto ret;
}
//
// Now go through each instance of the HTTPEXT counters and merge the data
// from that instance into the correct W3Ctrs counter instance according
// to server ID.
//
ppid = reinterpret_cast<PERF_INSTANCE_DEFINITION *>(
reinterpret_cast<LPBYTE>(ppot) + ppot->DefinitionLength );
for ( lcInstances = ppot->NumInstances;
lcInstances-- > 0;
ppid = reinterpret_cast<PERF_INSTANCE_DEFINITION *>(
reinterpret_cast<LPBYTE>(ppcb) + ppcb->ByteLength ) )
{
ppcb = reinterpret_cast<PERF_COUNTER_BLOCK *>(
reinterpret_cast<LPBYTE>(ppid) + ppid->ByteLength );
//
// Get the server ID of this instance.
//
DWORD dwServerIdInstance =
*reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + dwibServerId);
//
// If the server ID of this instance isn't the one
// we want then keep looking.
//
if ( dwServerIdInstance != dwServerId )
continue;
//
// The server IDs match, so sum in the info for this instance.
// NOTE: Since each vroot has its own instance, there may be
// multiple instances with the same server ID. Sum them all.
//
// Go through all the counters in the HTTPEXT instance
// and update the W3 statistics data.
//
for ( DWORD iCounter = 0;
iCounter < ppot->NumCounters;
iCounter++ )
{
PERF_COUNTER_DEFINITION * ppcd = &rgpcd[iCounter];
switch ( ppcd->CounterNameTitleIndex )
{
case HTTPEXT_COUNTER_TOTAL_GET_REQUESTS:
case HTTPEXT_COUNTER_TOTAL_HEAD_REQUESTS:
case HTTPEXT_COUNTER_TOTAL_POST_REQUESTS:
case HTTPEXT_COUNTER_TOTAL_DELETE_REQUESTS:
case HTTPEXT_COUNTER_TOTAL_OTHER_REQUESTS:
{
//
// These values are already recorded
// in the statistics, so don't do anything
// more with them here.
//
break;
}
case HTTPEXT_COUNTER_TOTAL_PUT_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalFilesReceived += dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_OPTIONS_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalOptions += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_COPY_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalCopy += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_MOVE_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalMove += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_MKCOL_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalMkcol += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_PROPFIND_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalPropfind += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_PROPPATCH_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalProppatch += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_SEARCH_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalSearch += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_LOCK_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalLock += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_UNLOCK_REQUESTS:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalUnlock += dwValue;
pW3Stats->TotalOthers -= dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_404_RESPONSES:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalNotFoundErrors += dwValue;
}
break;
}
case HTTPEXT_COUNTER_TOTAL_423_RESPONSES:
{
if ( ppcd->CounterType == PERF_COUNTER_RAWCOUNT &&
ppcd->CounterSize == sizeof(DWORD) )
{
DWORD dwValue = *reinterpret_cast<LPDWORD>(
reinterpret_cast<LPBYTE>(ppcb) + ppcd->CounterOffset );
pW3Stats->TotalLockedErrors += dwValue;
}
break;
}
default:
{
//
// We either don't care about or don't understand
// other counters, so skip them.
//
break;
}
}
}
}
ret:
if (lpbDavData)
delete [] lpbDavData;
return fRet;
}
// ========================================================================
//
// CLASS CW3MonitorInit
//
// Refcounted global initialization class that controls the lifetime of
// the singleton CW3Monitor instance. Calls to collect performance data
// are done in the scope of a reference to this class so that the server
// can be taken down on one thread while another thread is in the middle
// of -- or just beginning to -- collect data. Whichever thread releases
// the last reference to this class will be the one to close the counters.
//
class CW3MonitorInit : private RefCountedGlobal<CW3MonitorInit>
{
//
// Friend declarations required by RefCountedGlobal template
//
friend class Singleton<CW3MonitorInit>;
friend class RefCountedGlobal<CW3MonitorInit>;
// CREATORS
//
// Declared private to ensure that arbitrary instances
// of this class cannot be created. The Singleton
// template (declared as a friend above) controls
// the sole instance of this class.
//
CW3MonitorInit()
{
}
BOOL FInit()
{
return TRUE;
}
~CW3MonitorInit()
{
CW3Monitor::W3CloseDavPerformanceData();
}
// NOT IMPLEMENTED
//
CW3MonitorInit( const CW3MonitorInit& );
CW3MonitorInit& operator=( const CW3MonitorInit& );
public:
using RefCountedGlobal<CW3MonitorInit>::DwInitRef;
using RefCountedGlobal<CW3MonitorInit>::DeinitRef;
};
// ========================================================================
//
// PUBLIC INTERFACE
//
// ------------------------------------------------------------------------
//
// W3MergeDavPerformanceData()
//
EXTERN_C BOOL __fastcall
W3MergeDavPerformanceData( DWORD dwServerId, W3_STATISTICS_1 * pW3Stats )
{
BOOL fResult;
CW3MonitorInit::DwInitRef();
fResult = CW3Monitor::W3MergeDavPerformanceData( dwServerId, pW3Stats );
CW3MonitorInit::DeinitRef();
return fResult;
}
// ------------------------------------------------------------------------
//
// W3OpenDavPerformanceData()
//
EXTERN_C VOID __fastcall
W3OpenDavPerformanceData()
{
CW3MonitorInit::DwInitRef();
}
// ------------------------------------------------------------------------
//
// W3CloseDavPerformanceData()
//
EXTERN_C VOID __fastcall
W3CloseDavPerformanceData()
{
CW3MonitorInit::DeinitRef();
}