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.
 
 
 
 
 
 

564 lines
15 KiB

/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1993 **/
/**********************************************************************/
/*
perfdhcp.c
This file implements the Extensible Performance Objects for
the DHCP Server service.
FILE HISTORY:
KeithMo 07-Jun-1993 Created, based on RussBl's sample code.
RameshV 05-Aug-1998 Adapted to DHCP Server service.
Used Shared memory instead of LPC
*/
#define UNICODE 1
#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 <assert.h>
#include "dhcpctrs.h"
#include "perfmsg.h"
#include "perfutil.h"
#include "datadhcp.h"
#include "perfctr.h"
#pragma warning (disable : 4201)
#include <dhcpapi.h>
#pragma warning (default : 4201)
//
// Private globals.
//
DWORD cOpens = 0; // Active "opens" reference count.
BOOL fInitOK = FALSE; // TRUE if DLL initialized OK.
BOOL sfLogOpen = FALSE; //indicates whether the log is
//open or closed
BOOL sfErrReported = FALSE; //to prevent the same error from being
//logged continuously
#define LOCAL_SERVER TEXT("127.0.0.1")
//
// Public prototypes.
//
PM_OPEN_PROC OpenDhcpPerformanceData;
PM_COLLECT_PROC CollectDhcpPerformanceData;
PM_CLOSE_PROC CloseDhcpPerformanceData;
//
// Private helper functions
//
LPDHCP_PERF_STATS SharedMem;
HANDLE ShSegment = NULL;
BOOL fSharedMemInitialized = FALSE;
DWORD
InitSharedMem(
VOID
)
{
ULONG Error = ERROR_SUCCESS;
if( FALSE == fSharedMemInitialized ) {
// create named temporary mapping file
SharedMem = NULL;
ShSegment = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
sizeof(DHCP_PERF_STATS),
(LPCWSTR)DHCPCTR_SHARED_MEM_NAME
);
if( NULL != ShSegment ) {
// we have a file now map a view into it
SharedMem = (LPVOID) MapViewOfFile(
ShSegment,
FILE_MAP_READ,
0,
0,
sizeof(DHCP_PERF_STATS)
);
if( NULL != SharedMem ) {
fSharedMemInitialized = TRUE;
} else {
// unable to map view
Error = GetLastError();
CloseHandle(ShSegment);
ShSegment = NULL;
// SharedMem is NULL;
}
} else {
// unable to create file mapping
Error = GetLastError();
// ShSegment is NULL;
// SharedMem is NULL;
}
} else {
// already initialized so continue
}
return Error;
}
VOID
CleanupSharedMem(
VOID
)
{
if( FALSE == fSharedMemInitialized ) return;
if( NULL != SharedMem ) UnmapViewOfFile( SharedMem );
if( NULL != ShSegment ) CloseHandle( ShSegment );
SharedMem = NULL;
ShSegment = NULL;
fSharedMemInitialized = FALSE;
}
//
// Public functions.
//
/*******************************************************************
NAME: OpenDhcpPPerformanceData
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:
Pradeepb 20-July-1993 Created.`
RameshV 05-Aug-1998 Adapted for DHCP.
********************************************************************/
DWORD OpenDhcpPerformanceData( LPWSTR lpDeviceNames )
{
DWORD err = NO_ERROR;
DWORD dwFirstCounter = 0;
DWORD dwFirstHelp = 0;
//
// 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.
//
UNREFERENCED_PARAMETER (lpDeviceNames);
if( !fInitOK )
{
PERF_COUNTER_DEFINITION * pctr;
DWORD i;
HKEY DhcpKey;
REPORT_INFORMATION( DHCP_OPEN_ENTERED, LOG_VERBOSE );
//
// This is the *first* open.
//
err = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
(LPCWSTR)L"System\\CurrentControlSet\\Services\\DHCPServer\\Performance",
0,
KEY_READ,
&DhcpKey
);
if( ERROR_SUCCESS == err ) {
ULONG dwSize = sizeof(dwFirstCounter);
err = RegQueryValueExW(
DhcpKey,
(LPCWSTR)L"First Counter",
NULL,
NULL,
(LPBYTE)&dwFirstCounter,
&dwSize
);
RegCloseKey(DhcpKey);
}
if (err == ERROR_SUCCESS) {
// first help index is 1 more than first counter index as LODCTR installs it.
dwFirstHelp = dwFirstCounter + 1;
err = InitSharedMem();
if( ERROR_SUCCESS != err ) return err;
if (!MonOpenEventLog())
{
sfLogOpen = TRUE;
}
if( ERROR_SUCCESS == err ) {
//
// Update the object & counter name & help indicies.
//
DhcpDataDataDefinition.ObjectType.ObjectNameTitleIndex
+= dwFirstCounter;
DhcpDataDataDefinition.ObjectType.ObjectHelpTitleIndex
+= dwFirstHelp;
pctr = &DhcpDataDataDefinition.PacketsReceived;
for( i = 0 ; i < NUMBER_OF_DHCPDATA_COUNTERS ; i++ )
{
pctr->CounterNameTitleIndex += dwFirstCounter;
pctr->CounterHelpTitleIndex += dwFirstHelp;
pctr++;
}
//
// Remember that we initialized OK.
//
fInitOK = TRUE;
}
} else {
// if here, then either the perf key or the counter strings
// have not been installed so set the error code.
err = DHCP_NOT_INSTALLED;
REPORT_WARNING( DHCP_NOT_INSTALLED, LOG_DEBUG );
}
}
//
// Bump open counter.
//
if( err == NO_ERROR )
{
InterlockedIncrement(&cOpens);
}
//
// if sfLogOpen is FALSE, it means that all threads we closed the
// event log in CloseDHCPPerformanceData
//
if (!sfLogOpen)
{
MonOpenEventLog();
}
if( 0 == err ) {
REPORT_INFORMATION( DHCP_OPEN_SUCCESS, LOG_DEBUG );
} else {
REPORT_INFORMATION( DHCP_OPEN_FAILURE, LOG_DEBUG );
}
if (DHCP_NOT_INSTALLED == err) {
// sanitize the return value to avoid spamming the event log
err = ERROR_SUCCESS;
// this will prevent perflib from generating an error and
// since the fInitOK flag is still FLASE, all calls to the collect
// function will return no data.
// however, the DLL will still be loaded and the functions called
// even though there's no real point.
// returning an error code, however will spam the event log with
// error messages so this is the quitest way to go.
}
return err;
} // OpenDHCPPerformanceData
/*******************************************************************
NAME: CollectDhcpPerformanceData
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 CollectDhcpPerformanceData( LPWSTR lpValueName,
LPVOID * lppData,
LPDWORD lpcbTotalBytes,
LPDWORD lpNumObjectTypes )
{
DWORD dwQueryType;
ULONG cbRequired;
DWORD *pdwCounter;
DHCPDATA_COUNTER_BLOCK *pCounterBlock;
DHCPDATA_DATA_DEFINITION *pDhcpDataDataDefinition;
DWORD Status;
DHCP_PERF_STATS PerfStats;
//
// No need to even try if we failed to open...
//
if( NULL == lpValueName ) {
REPORT_INFORMATION( DHCP_COLLECT_ENTERED, LOG_VERBOSE );
} else {
REPORT_INFORMATION_DATA(
DHCP_COLLECT_ENTERED, LOG_VERBOSE,
(LPVOID) lpValueName, (DWORD)(wcslen(lpValueName)*sizeof(WCHAR))
);
}
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(
DhcpDataDataDefinition.ObjectType.ObjectNameTitleIndex,
lpValueName ) )
{
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return NO_ERROR;
}
}
//
// See if there's enough space.
//
pDhcpDataDataDefinition = (DHCPDATA_DATA_DEFINITION *)*lppData;
cbRequired = sizeof(DHCPDATA_DATA_DEFINITION) +
DHCPDATA_SIZE_OF_PERFORMANCE_DATA;
if( *lpcbTotalBytes < cbRequired )
{
DWORD Diff = (cbRequired - *lpcbTotalBytes );
//
// Nope.
//
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
REPORT_INFORMATION_DATA(
DHCP_COLLECT_NO_MEM, LOG_VERBOSE,
(PVOID) &Diff, sizeof(Diff) );
return ERROR_MORE_DATA;
}
//
// Copy the (constant, initialized) Object Type and counter definitions
// to the caller's data buffer
//
memmove( pDhcpDataDataDefinition,
&DhcpDataDataDefinition,
sizeof(DHCPDATA_DATA_DEFINITION) );
//
// Try to retrieve the data.
//
if( NULL == SharedMem ) {
Status = ERROR_INVALID_HANDLE;
} else {
Status = ERROR_SUCCESS;
}
if( Status != ERROR_SUCCESS )
{
//
// if we haven't logged the error yet, log it
//
if (!sfErrReported)
{
REPORT_ERROR(DHCP_COLLECT_ERR, LOG_USER);
sfErrReported = TRUE;
}
//
// Error retrieving statistics.
//
*lpcbTotalBytes = 0;
*lpNumObjectTypes = 0;
return NO_ERROR;
}
//
// Ahaa, we got the statistics, reset flag if set
//
if (sfErrReported)
{
sfErrReported = FALSE;
}
//
// Format the DHCP Server data.
//
pCounterBlock = (DHCPDATA_COUNTER_BLOCK *)( pDhcpDataDataDefinition + 1 );
pCounterBlock->PerfCounterBlock.ByteLength =
DHCPDATA_SIZE_OF_PERFORMANCE_DATA;
//
// Get the pointer to the first (DWORD) counter. This
// pointer *must* be quadword aligned.
//
pdwCounter = (DWORD *)( pCounterBlock + 1 );
ASSERT( ( (DWORD_PTR)pdwCounter & 3 ) == 0 );
//
// Move the DWORDs into the buffer.
//
PerfStats = *SharedMem;
PerfStats.dwNumMilliSecondsProcessed /= (
1 + PerfStats.dwNumPacketsProcessed
);
memcpy( (LPBYTE)pdwCounter, (LPBYTE)&PerfStats, sizeof(ULONG)*NUMBER_OF_DHCPDATA_COUNTERS);
pdwCounter += NUMBER_OF_DHCPDATA_COUNTERS;
//
// Update arguments for return.
//
*lppData = (PVOID)pdwCounter;
*lpNumObjectTypes = 1;
*lpcbTotalBytes = (DWORD)((BYTE *)pdwCounter - (BYTE *)pDhcpDataDataDefinition);
//
// Success! Honest!!
//
REPORT_INFORMATION( DHCP_COLLECT_SUCCESS, LOG_VERBOSE );
return NO_ERROR;
} // CollectDHCPPerformanceData
/*******************************************************************
NAME: CloseDHCPPerformanceData
SYNOPSIS: Terminates the performance counters.
RETURNS: DWORD - Win32 status code.
HISTORY:
KeithMo 07-Jun-1993 Created.
********************************************************************/
DWORD CloseDhcpPerformanceData( VOID )
{
LONG lOpens;
//
// No real cleanup to do here.
//
REPORT_INFORMATION( DHCP_CLOSE_ENTERED, LOG_VERBOSE );
//
// NOTE: The interlocked operations are used just as a safeguard.
// As with all perflibs, these 3 functions should be called within
// a data mutex.
//
lOpens = InterlockedDecrement(&cOpens);
assert (lOpens >= 0);
if (lOpens == 0)
{
//
// unbind from the nameserver. There could be synch. problems since
// sfLogOpen is changed in both Open and Close functions. This at the
// max. will affect logging. It being unclear at this point whether or
// not Open gets called multiple times (from all looks of it, it is only
// called once), this flag may even not be necessary.
//
MonCloseEventLog();
sfLogOpen = FALSE;
CleanupSharedMem();
}
return NO_ERROR;
} // CloseDHCPPerformanceData