|
|
/**********************************************************************/ /** Microsoft Windows NT **/ /** Copyright(c) Microsoft Corp., 1993 **/ /**********************************************************************/
/*
infoperf.c
This file implements the Extensible Performance Objects for the common INFO counters
FILE HISTORY: KeithMo 07-Jun-1993 Created, based on RussBl's sample code. MuraliK 02-Jun-1995 Added Counters for Atq I/O requests SophiaC 16-Oct-1995 Info/Access Product Split MuraliK 16-Nov-1995 Removed undoc apis
*/
#include <windows.h>
#include <winperf.h>
#include <lm.h>
#include <inetinfo.h>
#include <string.h>
#include <stdlib.h>
#include <infoctrs.h>
#include <infodata.h>
#include <perfutil.h>
#include <iis64.h>
#include "infomsg.h"
# include "apiutil.h"
//
// Private constants.
//
#define APP_NAME (TEXT("IISInfoCtrs"))
//
// Private globals.
//
DWORD cOpens = 0; // Active "opens" reference count.
BOOL fInitOK = FALSE; // TRUE if DLL initialized OK.
HANDLE hEventLog = NULL; // event log handle
#if DBG
DWORD INFODebug = 0; // Debug behaviour flags.
#endif // DBG
//
// Public prototypes.
//
PM_OPEN_PROC OpenINFOPerformanceData; PM_COLLECT_PROC CollectINFOPerformanceData; PM_CLOSE_PROC CloseINFOPerformanceData;
//
// Public functions.
//
/*******************************************************************
NAME: OpenINFOPerformanceData
SYNOPSIS: Initializes the data structures used to communicate performance counters with the registry.
ENTRY: lpDeviceNames - Poitner to object ID of each device to be opened.
RETURNS: DWORD - Win32 status code.
HISTORY: KeithMo 07-Jun-1993 Created.
********************************************************************/ DWORD OpenINFOPerformanceData( LPWSTR lpDeviceNames ) { DWORD err = NO_ERROR; HKEY hkey = NULL; DWORD size; DWORD type; DWORD dwFirstCounter; DWORD dwFirstHelp; PERF_COUNTER_DEFINITION * pctr; DWORD i;
//
// Since SCREG is multi-threaded and will call this routine in
// order to service remote performance queries, this library
// must keep track of how many times it has been opened (i.e.
// how many threads have accessed it). The registry routines will
// limit access to the initialization routine to only one thread
// at a time so synchronization (i.e. reentrancy) should not be
// a problem.
//
if( !fInitOK ) {
//
// This is the *first* open.
//
// open the event log interface
if (hEventLog == NULL) { hEventLog = RegisterEventSource ( (LPSTR)NULL, // on the local machine
APP_NAME); // register the name to allow message lookup
}
//
// Open the HTTP Server service's Performance key.
//
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, INFO_PERFORMANCE_KEY, 0, KEY_READ, &hkey );
if( err == NO_ERROR ) { //
// Read the first counter DWORD.
//
size = sizeof(DWORD);
err = RegQueryValueEx( hkey, "First Counter", NULL, &type, (LPBYTE)&dwFirstCounter, &size ); if( err == NO_ERROR ) { //
// Read the first help DWORD.
//
size = sizeof(DWORD);
err = RegQueryValueEx( hkey, "First Help", NULL, &type, (LPBYTE)&dwFirstHelp, &size );
if ( err == NO_ERROR ) { //
// Update the object & counter name & help indicies.
//
INFODataDefinition.INFOObjectType.ObjectNameTitleIndex += dwFirstCounter; INFODataDefinition.INFOObjectType.ObjectHelpTitleIndex += dwFirstHelp;
pctr = &INFODataDefinition.INFOTotalAllowedRequests;
for( i = 0 ; i < NUMBER_OF_INFO_COUNTERS ; i++ ) { pctr->CounterNameTitleIndex += dwFirstCounter; pctr->CounterHelpTitleIndex += dwFirstHelp; pctr++; }
//
// Remember that we initialized OK.
//
fInitOK = TRUE; //
// Bump open counter.
//
cOpens++;
// return success
err = ERROR_SUCCESS; } else { // log event
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, IIS_INFO_UNABLE_READ_FIRST_HELP, (PSID)NULL, 0, sizeof (err), NULL, (PVOID)(&err)); } } else { // log event
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, IIS_INFO_UNABLE_READ_FIRST_COUNTER, (PSID)NULL, 0, sizeof (err), NULL, (PVOID)(&err)); } //
// Close the registry if we managed to actually open it.
//
if( hkey != NULL ) { RegCloseKey( hkey ); hkey = NULL; } } else { // log event
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, IIS_INFO_UNABLE_OPEN_PERF_KEY, (PSID)NULL, 0, sizeof (err), NULL, (PVOID)(&err)); } }
return err;
} // OpenINFOPerformanceData
/*******************************************************************
NAME: CollectINFOPerformanceData
SYNOPSIS: Initializes the data structures used to communicate
ENTRY: lpValueName - The name of the value to retrieve.
lppData - On entry contains a pointer to the buffer to receive the completed PerfDataBlock & subordinate structures. On exit, points to the first bytes *after* the data structures added by this routine.
lpcbTotalBytes - On entry contains a pointer to the size (in BYTEs) of the buffer referenced by lppData. On exit, contains the number of BYTEs added by this routine.
lpNumObjectTypes - Receives the number of objects added by this routine.
RETURNS: DWORD - Win32 status code. MUST be either NO_ERROR or ERROR_MORE_DATA.
HISTORY: KeithMo 07-Jun-1993 Created.
********************************************************************/ DWORD CollectINFOPerformanceData( LPWSTR lpValueName, LPVOID * lppData, LPDWORD lpcbTotalBytes, LPDWORD lpNumObjectTypes ) { DWORD dwQueryType; ULONG cbRequired; DWORD * pdwCounter; INFO_COUNTER_BLOCK * pCounterBlock; INFO_DATA_DEFINITION * pINFODataDefinition; INET_INFO_STATISTICS_0 * pINFOStats; NET_API_STATUS neterr;
//
// No need to even try if we failed to open...
//
if( !fInitOK ) { *lpcbTotalBytes = 0; *lpNumObjectTypes = 0;
//
// According to the Performance Counter design, this
// is a successful exit. Go figure.
//
return NO_ERROR; }
//
// Determine the query type.
//
dwQueryType = GetQueryType( lpValueName );
if (( dwQueryType == QUERY_FOREIGN ) || ( dwQueryType == QUERY_COSTLY )) { //
// We don't do foreign or Costly queries.
//
*lpcbTotalBytes = 0; *lpNumObjectTypes = 0;
return NO_ERROR; }
if( dwQueryType == QUERY_ITEMS ) { //
// The registry is asking for a specific object. Let's
// see if we're one of the chosen.
//
if( !IsNumberInUnicodeList( INFODataDefinition.INFOObjectType.ObjectNameTitleIndex, lpValueName ) ) { *lpcbTotalBytes = 0; *lpNumObjectTypes = 0;
return NO_ERROR; } }
//
// See if there's enough space.
//
pINFODataDefinition = (INFO_DATA_DEFINITION *)*lppData;
//
// Try to retrieve the data.
//
neterr = InetInfoQueryStatistics( NULL, 0, 0, (LPBYTE *)&pINFOStats );
if( neterr == NERR_Success ) {
cbRequired = sizeof(INFO_DATA_DEFINITION) + SIZE_OF_INFO_PERFORMANCE_DATA;
if( *lpcbTotalBytes < cbRequired ) { //
// Nope.
//
*lpcbTotalBytes = 0; *lpNumObjectTypes = 0;
return ERROR_MORE_DATA; }
//
// Copy the (constant, initialized) Object Type and counter definitions
// to the caller's data buffer
//
memmove( pINFODataDefinition, &INFODataDefinition, sizeof(INFO_DATA_DEFINITION) );
//
// Format the INFO Server data.
//
pCounterBlock = (INFO_COUNTER_BLOCK *)( pINFODataDefinition + 1 );
pCounterBlock->PerfCounterBlock.ByteLength = SIZE_OF_INFO_PERFORMANCE_DATA;
//
// Now move the DWORDs into the buffer.
//
pdwCounter = (DWORD *)(pCounterBlock + 1);
//
// ATQ Global counters
//
*pdwCounter++ = pINFOStats->AtqCtrs.TotalAllowedRequests; *pdwCounter++ = pINFOStats->AtqCtrs.TotalBlockedRequests; *pdwCounter++ = pINFOStats->AtqCtrs.TotalRejectedRequests; *pdwCounter++ = pINFOStats->AtqCtrs.CurrentBlockedRequests; *pdwCounter++ = pINFOStats->AtqCtrs.MeasuredBandwidth;
//
// File Handle Cache counters
//
*pdwCounter++ = pINFOStats->CacheCtrs.FilesCached; *pdwCounter++ = pINFOStats->CacheCtrs.TotalFilesCached; *pdwCounter++ = pINFOStats->CacheCtrs.FileHits; *pdwCounter++ = pINFOStats->CacheCtrs.FileMisses; *pdwCounter++ = pINFOStats->CacheCtrs.FileHits; *pdwCounter++ = ( pINFOStats->CacheCtrs.FileHits + pINFOStats->CacheCtrs.FileMisses); *pdwCounter++ = pINFOStats->CacheCtrs.FileFlushes;
// 64BIT BUGBUG: need to change the caller to expect int64 and then
// put in the whole 64 bit value here
// *((DWORDLONG *)pdwCounter) =
*pdwCounter++ = (DWORD)pINFOStats->CacheCtrs.CurrentFileCacheSize;
// pdwCounter += sizeof(DWORDLONG) / sizeof(*pdwCounter);
// *((DWORDLONG *)pdwCounter) =
*pdwCounter++ = (DWORD)pINFOStats->CacheCtrs.MaximumFileCacheSize;
// pdwCounter += sizeof(DWORDLONG) / sizeof(*pdwCounter);
*pdwCounter++ = pINFOStats->CacheCtrs.FlushedEntries; *pdwCounter++ = pINFOStats->CacheCtrs.TotalFlushed;
//
// URI Cache counters
//
*pdwCounter++ = pINFOStats->CacheCtrs.URICached; *pdwCounter++ = pINFOStats->CacheCtrs.TotalURICached; *pdwCounter++ = pINFOStats->CacheCtrs.URIHits; *pdwCounter++ = pINFOStats->CacheCtrs.URIMisses; *pdwCounter++ = pINFOStats->CacheCtrs.URIHits; *pdwCounter++ = ( pINFOStats->CacheCtrs.URIHits + pINFOStats->CacheCtrs.URIMisses); *pdwCounter++ = pINFOStats->CacheCtrs.URIFlushes; *pdwCounter++ = pINFOStats->CacheCtrs.TotalURIFlushed;
//
// Blob Cache Counters
//
*pdwCounter++ = pINFOStats->CacheCtrs.BlobCached; *pdwCounter++ = pINFOStats->CacheCtrs.TotalBlobCached; *pdwCounter++ = pINFOStats->CacheCtrs.BlobHits; *pdwCounter++ = pINFOStats->CacheCtrs.BlobMisses; *pdwCounter++ = pINFOStats->CacheCtrs.BlobHits; *pdwCounter++ = ( pINFOStats->CacheCtrs.BlobHits + pINFOStats->CacheCtrs.BlobMisses); *pdwCounter++ = pINFOStats->CacheCtrs.BlobFlushes; *pdwCounter++ = pINFOStats->CacheCtrs.TotalBlobFlushed;
//
// Update arguments for return.
//
*lppData = (PVOID)pdwCounter; *lpNumObjectTypes = 1; *lpcbTotalBytes = DIFF((BYTE *)pdwCounter - (BYTE *)pINFODataDefinition);
//
// Free the API buffer.
//
MIDL_user_free( (LPBYTE)pINFOStats );
//
// Success! Honest!!
//
} else { //
// Error retrieving statistics.
//
// if the server is down, we don't log an error.
if ( !( neterr == RPC_S_SERVER_UNAVAILABLE || neterr == RPC_S_UNKNOWN_IF || neterr == ERROR_SERVICE_NOT_ACTIVE || neterr == RPC_S_CALL_FAILED_DNE )) {
// log event
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, IIS_INFO_UNABLE_QUERY_IIS_INFO_DATA, (PSID)NULL, 0, sizeof (neterr), NULL, (PVOID)(&neterr)); }
cbRequired = sizeof(INFO_DATA_DEFINITION) + SIZE_OF_INFO_PERFORMANCE_DATA;
if( *lpcbTotalBytes < cbRequired ) { //
// Nope.
//
*lpcbTotalBytes = 0; *lpNumObjectTypes = 0;
return ERROR_MORE_DATA; }
// Attempt to atlest provide the definition
// for the counters. This is so WMI can know
// that these counters exist.
memmove( pINFODataDefinition, &INFODataDefinition, sizeof(INFO_DATA_DEFINITION) );
((PERF_OBJECT_TYPE*) pINFODataDefinition)->NumInstances = PERF_NO_INSTANCES; ((PERF_OBJECT_TYPE*) pINFODataDefinition)->TotalByteLength = cbRequired;
// Copy in the actual data for global
memset ( (LPVOID) ( pINFODataDefinition + 1 ), 0, SIZE_OF_INFO_PERFORMANCE_DATA );
// This is setting the size in the structure, it is the first
// DWORD in the INFO_COUNTER_BLOCK.
*((DWORD*) (pINFODataDefinition + 1)) = SIZE_OF_INFO_PERFORMANCE_DATA;
*lpcbTotalBytes = cbRequired; *lpNumObjectTypes = 1; *lppData = (LPBYTE) pINFODataDefinition + cbRequired;
}
return NO_ERROR;
} // CollectINFOPerformanceData
/*******************************************************************
NAME: CloseINFOPerformanceData
SYNOPSIS: Terminates the performance counters.
RETURNS: DWORD - Win32 status code.
HISTORY: KeithMo 07-Jun-1993 Created.
********************************************************************/ DWORD CloseINFOPerformanceData( VOID ) { //
// No real cleanup to do here.
//
if (--cOpens == 0) { if (hEventLog != NULL) DeregisterEventSource (hEventLog); }
return NO_ERROR;
} // CloseINFOPerformanceData
|