mirror of https://github.com/lianthony/NT4.0
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.
454 lines
10 KiB
454 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
perfgd.c
|
|
|
|
Abstract:
|
|
|
|
This module implements extendible performance objects for
|
|
Gopher service objects and counters.
|
|
|
|
|
|
Author:
|
|
|
|
Murali R. Krishnan ( MuraliK ) 24-Nov-1994
|
|
|
|
Project:
|
|
|
|
Gopher Server Performance Counters DLL
|
|
|
|
Functions Exported:
|
|
|
|
DWORD OpenGdPerformanceData()
|
|
DWORD CollectGdPerformanceData()
|
|
DWORD CloseGdPerformanceData()
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
/************************************************************
|
|
* Include Headers
|
|
************************************************************/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
#include <lm.h>
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <gdctrs.h>
|
|
#include <perfmsg.h>
|
|
#include <perfutil.h>
|
|
|
|
# include <gddata.h>
|
|
# include <gdregs.h>
|
|
# include <inetinfo.h>
|
|
|
|
|
|
//
|
|
// Private globals.
|
|
//
|
|
|
|
static DWORD cOpens = 0; // Active "opens" reference count.
|
|
static BOOL fInitOK = FALSE; // TRUE if DLL initialized OK.
|
|
|
|
DWORD DbgDebug = 0xffffffc0;
|
|
|
|
//
|
|
// Public prototypes.
|
|
//
|
|
|
|
PM_OPEN_PROC OpenGdPerformanceData;
|
|
PM_COLLECT_PROC CollectGdPerformanceData;
|
|
PM_CLOSE_PROC CloseGdPerformanceData;
|
|
|
|
|
|
/************************************************************
|
|
* Functions
|
|
************************************************************/
|
|
|
|
DWORD OpenGdPerformanceData( LPWSTR lpDeviceNames )
|
|
/*++
|
|
Description:
|
|
|
|
Initializes the data structures used to communicate performance
|
|
counters with the registry.
|
|
|
|
Arguments:
|
|
lpszDeviceNames: pointer to object ID of each device to be opened
|
|
|
|
Returns:
|
|
Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
|
|
|
|
//
|
|
// 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 )
|
|
{
|
|
HKEY hkey = NULL;
|
|
DWORD dwFirstCounter;
|
|
DWORD dwFirstHelp;
|
|
DWORD size = 0;
|
|
DWORD type;
|
|
|
|
|
|
//
|
|
// Open Gopher service's performance counter
|
|
//
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
GOPHERD_PERFORMANCE_KEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hkey );
|
|
|
|
if( err == NO_ERROR ) {
|
|
|
|
//
|
|
// Read the first counter DWORD.
|
|
//
|
|
|
|
size = sizeof(DWORD);
|
|
|
|
err = RegQueryValueEx( hkey, // key to registry
|
|
"First Counter", // value name
|
|
NULL, // lpvReserved
|
|
&type, // address for type
|
|
(LPBYTE)&dwFirstCounter, // address for data
|
|
&size ); // address for size;
|
|
|
|
}
|
|
|
|
if( err == NO_ERROR ) {
|
|
|
|
//
|
|
// Read the first counter DWORD.
|
|
//
|
|
|
|
size = sizeof(DWORD);
|
|
|
|
err = RegQueryValueEx( hkey, // key to registry
|
|
"First Help", // value name
|
|
NULL, // lpvReserved
|
|
&type, // address for type
|
|
(LPBYTE)&dwFirstHelp, // address for data
|
|
&size ); // address for size;
|
|
}
|
|
|
|
if ( err == NO_ERROR) {
|
|
|
|
DWORD i;
|
|
PERF_COUNTER_DEFINITION * pctr;
|
|
|
|
//
|
|
// Update the object & counter name & help indicies.
|
|
//
|
|
|
|
GdDataDefinition.GdObjectType.ObjectNameTitleIndex
|
|
+= dwFirstCounter;
|
|
GdDataDefinition.GdObjectType.ObjectHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
|
|
pctr = &GdDataDefinition.GdBytesSent;
|
|
|
|
for( i = 0 ; i < NUMBER_OF_GD_COUNTERS ; i++ ) {
|
|
pctr->CounterNameTitleIndex += dwFirstCounter;
|
|
pctr->CounterHelpTitleIndex += dwFirstHelp;
|
|
pctr++;
|
|
}
|
|
|
|
//
|
|
// Remember that we initialized OK.
|
|
//
|
|
|
|
fInitOK = TRUE;
|
|
}
|
|
|
|
if ( hkey != NULL) {
|
|
|
|
DWORD errClose;
|
|
|
|
errClose = RegCloseKey( hkey); // Ignore the error
|
|
|
|
hkey = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Bump open counter.
|
|
//
|
|
|
|
if ( err == NO_ERROR) {
|
|
|
|
cOpens++;
|
|
}
|
|
|
|
|
|
return ( err);
|
|
|
|
} // OpenGdPerformanceData()
|
|
|
|
|
|
|
|
|
|
DWORD CollectGdPerformanceData(
|
|
IN LPWSTR lpValueName,
|
|
IN OUT LPVOID * lppData,
|
|
IN OUT LPDWORD lpcbTotalBytes,
|
|
IN OUT LPDWORD lpNumObjectTypes )
|
|
/*++
|
|
Description:
|
|
|
|
Initializes the data structures used for communicating the
|
|
performance counter values requested.
|
|
|
|
Arguments:
|
|
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:
|
|
Win32 error code.
|
|
Must be either ERROR_MORE_DATA or NO_ERROR.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwQueryType;
|
|
ULONG cbRequired;
|
|
DWORD * pdwCounter;
|
|
LARGE_INTEGER * pliCounter;
|
|
GD_COUNTER_BLOCK * pCounterBlock;
|
|
GD_DATA_DEFINITION * pGdDataDefinition;
|
|
GOPHERD_STATISTICS_INFO GdStats;
|
|
LPGOPHERD_STATISTICS_INFO pGdStats = & GdStats;
|
|
DWORD dwErr;
|
|
|
|
//
|
|
// 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 ) {
|
|
|
|
//
|
|
// We don't do foreign 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(
|
|
GdDataDefinition.GdObjectType.ObjectNameTitleIndex,
|
|
lpValueName ) )
|
|
{
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if there's enough space.
|
|
//
|
|
|
|
cbRequired = sizeof(GD_DATA_DEFINITION) + SIZE_OF_GD_PERFORMANCE_DATA;
|
|
|
|
if( *lpcbTotalBytes < cbRequired ) {
|
|
//
|
|
// Nope.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
pGdDataDefinition = (GD_DATA_DEFINITION *)*lppData;
|
|
|
|
//
|
|
// Copy the (constant, initialized) Object Type and counter definitions
|
|
// to the caller's data buffer
|
|
//
|
|
|
|
memmove( pGdDataDefinition,
|
|
&GdDataDefinition,
|
|
sizeof(GD_DATA_DEFINITION) );
|
|
|
|
//
|
|
// Try to retrieve the data.
|
|
//
|
|
|
|
dwErr = GdGetStatistics( NULL,
|
|
(LPBYTE ) pGdStats );
|
|
|
|
if( dwErr != NO_ERROR) {
|
|
|
|
//
|
|
// Error retrieving statistics.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Format the Gopher Server data.
|
|
//
|
|
|
|
pCounterBlock = (GD_COUNTER_BLOCK *)( pGdDataDefinition + 1 );
|
|
|
|
pCounterBlock->PerfCounterBlock.ByteLength = SIZE_OF_GD_PERFORMANCE_DATA;
|
|
|
|
//
|
|
// Get the pointer to the first (LARGE_INTEGER) counter. This
|
|
// pointer *must* be quadword aligned.
|
|
//
|
|
|
|
pliCounter = (LARGE_INTEGER *)( pCounterBlock + 1 );
|
|
|
|
//
|
|
// Move the LARGE_INTEGERs into the buffer.
|
|
//
|
|
|
|
*pliCounter++ = pGdStats->TotalBytesSent;
|
|
*pliCounter++ = pGdStats->TotalBytesRecvd;
|
|
|
|
pliCounter->QuadPart = ( pGdStats->TotalBytesSent.QuadPart +
|
|
pGdStats->TotalBytesRecvd.QuadPart);
|
|
*pliCounter++;
|
|
|
|
//
|
|
// Now move the DWORDs into the buffer.
|
|
//
|
|
|
|
pdwCounter = (DWORD *)pliCounter;
|
|
|
|
|
|
*pdwCounter++ = pGdStats->TotalFilesSent;
|
|
*pdwCounter++ = pGdStats->TotalDirectoryListings;
|
|
*pdwCounter++ = pGdStats->TotalSearches;
|
|
*pdwCounter++ = pGdStats->CurrentAnonymousUsers;
|
|
*pdwCounter++ = pGdStats->CurrentNonAnonymousUsers;
|
|
*pdwCounter++ = pGdStats->TotalAnonymousUsers;
|
|
*pdwCounter++ = pGdStats->TotalNonAnonymousUsers;
|
|
*pdwCounter++ = pGdStats->MaxAnonymousUsers;
|
|
*pdwCounter++ = pGdStats->MaxNonAnonymousUsers;
|
|
*pdwCounter++ = pGdStats->CurrentConnections;
|
|
*pdwCounter++ = pGdStats->MaxConnections;
|
|
*pdwCounter++ = pGdStats->ConnectionAttempts;
|
|
*pdwCounter++ = pGdStats->LogonAttempts;
|
|
*pdwCounter++ = pGdStats->AbortedAttempts;
|
|
*pdwCounter++ = pGdStats->ErroredConnections;
|
|
*pdwCounter++ = pGdStats->GopherPlusRequests;
|
|
|
|
//
|
|
// Update arguments for return.
|
|
//
|
|
|
|
*lppData = (PVOID)pdwCounter;
|
|
*lpNumObjectTypes = 1;
|
|
*lpcbTotalBytes = (BYTE *)pdwCounter - (BYTE *)pGdDataDefinition;
|
|
|
|
//
|
|
// Success! Honest!!
|
|
//
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CollectGdPerformanceData()
|
|
|
|
|
|
|
|
|
|
DWORD CloseGdPerformanceData( VOID )
|
|
/*++
|
|
Description:
|
|
Terminates ther performance counters.
|
|
|
|
Returns:
|
|
DWORD. Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// No real cleanup to do here. Just decrement the count of opens.
|
|
//
|
|
|
|
cOpens--;
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CloseGdPerformanceData
|
|
|
|
|
|
|
|
/************************ End of File ***********************/
|
|
|