|
|
/****************************************************************************
PROGRAM: NWPerf.c
PURPOSE: Contains library routines for providing perfmon with data
FUNCTIONS: *******************************************************************************/ #include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winperf.h>
#include <ntddnwfs.h>
#include "NWPerf.h"
#include "prfutil.h"
#ifndef QFE_BUILD
#include "ntprfctr.h"
#endif
BOOL gbInitOK = FALSE;
HANDLE hNetWareRdr ; extern NW_DATA_DEFINITION NWDataDefinition;
#ifdef QFE_BUILD
TCHAR PerformanceKeyName [] = TEXT("SYSTEM\\CurrentControlSet\\Services\\NWrdr\\Performance"); TCHAR FirstCounterKeyName [] = TEXT("First Counter"); TCHAR FirstHelpKeyName [] = TEXT("First Help"); #endif
/****************************************************************************
FUNCTION: OpenNetWarePerformanceData
Purpose: This routine also initializes the data structures used to pass data back to the registry
Return: None. r****************************************************************************/ DWORD APIENTRY OpenNetWarePerformanceData( LPWSTR pInstances ) {
LONG status; #ifdef QFE_BUILD
HKEY hKeyPerf = 0; DWORD size; DWORD type; DWORD dwFirstCounter; DWORD dwFirstHelp; #else
NT_PRODUCT_TYPE ProductType; DWORD dwFirstCounter = NWCS_CLIENT_COUNTER_INDEX ; DWORD dwFirstHelp = NWCS_CLIENT_HELP_INDEX ; #endif
IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING DeviceNameU; OBJECT_ATTRIBUTES ObjectAttributes;
#ifdef QFE_BUILD
status = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, PerformanceKeyName, 0L, KEY_ALL_ACCESS, &hKeyPerf );
if (status != ERROR_SUCCESS) { goto OpenExitPoint; }
size = sizeof (DWORD); status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type, (LPBYTE)&dwFirstCounter, &size);
if (status != ERROR_SUCCESS) { goto OpenExitPoint; }
size = sizeof (DWORD); status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName, 0L, &type, (LPBYTE)&dwFirstHelp, &size );
if (status != ERROR_SUCCESS) { goto OpenExitPoint; } #endif
//
// NOTE: the initialization program could also retrieve
// LastCounter and LastHelp if they wanted to do
// bounds checking on the new number. e.g.
//
// counter->CounterNameTitleIndex += dwFirstCounter;
// if (counter->CounterNameTitleIndex > dwLastCounter) {
// LogErrorToEventLog (INDEX_OUT_OF_BOUNDS);
// }
NWDataDefinition.NWObjectType.ObjectNameTitleIndex += dwFirstCounter; NWDataDefinition.NWObjectType.ObjectHelpTitleIndex += dwFirstHelp;
// Counters not defined in Redirector, setup the correct IDs
NWDataDefinition.PacketBurstRead.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.PacketBurstRead.CounterHelpTitleIndex += dwFirstHelp; NWDataDefinition.PacketBurstReadTimeouts.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.PacketBurstReadTimeouts.CounterHelpTitleIndex += dwFirstHelp; NWDataDefinition.PacketBurstWrite.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.PacketBurstWrite.CounterHelpTitleIndex += dwFirstHelp; NWDataDefinition.PacketBurstWriteTimeouts.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.PacketBurstWriteTimeouts.CounterHelpTitleIndex += dwFirstHelp; NWDataDefinition.PacketBurstIO.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.PacketBurstIO.CounterHelpTitleIndex += dwFirstHelp; NWDataDefinition.NetWare2XConnects.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.NetWare2XConnects.CounterHelpTitleIndex += dwFirstHelp; NWDataDefinition.NetWare3XConnects.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.NetWare3XConnects.CounterHelpTitleIndex += dwFirstHelp; NWDataDefinition.NetWare4XConnects.CounterNameTitleIndex += dwFirstCounter; NWDataDefinition.NetWare4XConnects.CounterHelpTitleIndex += dwFirstHelp;
#ifndef QFE_BUILD
// Check for WorkStation or Server and use the gateway indexes if
// currently running on Server.
// If RtlGetNtProductType is not successful or ProductType is
// WinNt machine, ObjectNameTitleIndex and ObjectHelpTitleIndex are set
// to the correct values already.
#ifdef GATEWAY_ENABLED
if ( RtlGetNtProductType( &ProductType)) { if ( ProductType != NtProductWinNt ) { NWDataDefinition.NWObjectType.ObjectNameTitleIndex = NWCS_GATEWAY_COUNTER_INDEX; NWDataDefinition.NWObjectType.ObjectHelpTitleIndex = NWCS_GATEWAY_HELP_INDEX; } } #endif
#endif
hNetWareRdr = NULL;
RtlInitUnicodeString(&DeviceNameU, DD_NWFS_DEVICE_NAME_U);
InitializeObjectAttributes(&ObjectAttributes, &DeviceNameU, OBJ_CASE_INSENSITIVE, NULL, NULL );
status = NtCreateFile(&hNetWareRdr, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
gbInitOK = TRUE; // ok to use this function
status = ERROR_SUCCESS; // for successful exit
#ifdef QFE_BUILD
OpenExitPoint: if (hKeyPerf) RegCloseKey (hKeyPerf); // close key to registry
#endif
return ((DWORD) status); }
/****************************************************************************
FUNCTION: CollectNetWarePerformanceData
Purpose: This routine will return the data for the NetWare counters.
Arguments:IN LPWSTR lpValueName pointer to a wide character string passed by registry.
IN OUT LPVOID *lppData IN: pointer to the address of the buffer to receive the completed PerfDataBlock and subordinate structures. This routine will append its data to the buffer starting at the point referenced by *lppData.
OUT: points to the first byte after the data structure added by this routine. This routine updated the value at lppdata after appending its data.
IN OUT LPDWORD lpcbTotalBytes IN: the address of the DWORD that tells the size in bytes of the buffer referenced by the lppData argument
OUT: the number of bytes added by this routine is written to the DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes IN: the address of the DWORD to receive the number of objects added by this routine
OUT: the number of objects added by this routine is written to the DWORD pointed to by this argument
Return: ERROR_MORE_DATA if buffer passed is too small to hold data any error conditions encountered are reported to the event log if event logging is enabled.
ERROR_SUCCESS if success or any other error. Errors, however are also reported to the event log.
****************************************************************************/ DWORD APIENTRY CollectNetWarePerformanceData( IN LPWSTR lpValueName, IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes) { ULONG SpaceNeeded; PDWORD pdwCounter; DWORD dwQueryType; PERF_COUNTER_BLOCK *pPerfCounterBlock; NW_DATA_DEFINITION *pNWDataDefinition; LONG status; NW_REDIR_STATISTICS NWRdrStatistics; LARGE_INTEGER UNALIGNED *pliCounter; IO_STATUS_BLOCK IoStatusBlock;
//
// before doing anything else, see if Open went OK
//
if (!gbInitOK) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; // yes, this is a successful exit
}
// see if this is a foreign (i.e. non-NT) computer data request
//
dwQueryType = GetQueryType (lpValueName);
if (dwQueryType == QUERY_FOREIGN) { // this routine does not service requests for data from
// Non-NT computers
*lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; }
// If the caller only wanted some counter, check if we have 'em
if (dwQueryType == QUERY_ITEMS){ if ( !(IsNumberInUnicodeList ( NWDataDefinition.NWObjectType.ObjectNameTitleIndex, lpValueName))) { // request received for data object not provided by this routine
*lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } }
pNWDataDefinition = (NW_DATA_DEFINITION *) *lppData;
SpaceNeeded = sizeof(NW_DATA_DEFINITION) + SIZE_OF_COUNTER_BLOCK;
if ( *lpcbTotalBytes < SpaceNeeded ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ((DWORD) ERROR_MORE_DATA); }
//
// Copy the (constant, initialized) Object Type and counter definitions
// to the caller's data buffer
//
memmove( pNWDataDefinition, &NWDataDefinition, sizeof(NW_DATA_DEFINITION) );
// Point at the byte right after all the definitions
pPerfCounterBlock = (PERF_COUNTER_BLOCK *) &pNWDataDefinition[1];
// The first DWORD should specify the size of actual data block
pPerfCounterBlock->ByteLength = SIZE_OF_COUNTER_BLOCK;
// Move the pointer up
pdwCounter = (PDWORD) (&pPerfCounterBlock[1]);
// Open the NetWare data
if ( hNetWareRdr != NULL) { status = NtFsControlFile(hNetWareRdr, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_GET_STATISTICS, NULL, 0, &NWRdrStatistics, sizeof(NWRdrStatistics) ); } if ( hNetWareRdr != NULL && NT_SUCCESS(status) ) {
pliCounter = (LARGE_INTEGER UNALIGNED * ) (&pPerfCounterBlock[1]);
pliCounter->QuadPart = NWRdrStatistics.BytesReceived.QuadPart + NWRdrStatistics.BytesTransmitted.QuadPart;
pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = NWRdrStatistics.ReadOperations + NWRdrStatistics.WriteOperations; pliCounter = (LARGE_INTEGER UNALIGNED * ) ++pdwCounter; pliCounter->QuadPart = NWRdrStatistics.NcpsReceived.QuadPart + NWRdrStatistics.NcpsTransmitted.QuadPart; *++pliCounter = NWRdrStatistics.BytesReceived; *++pliCounter = NWRdrStatistics.NcpsReceived; *++pliCounter = NWRdrStatistics.BytesTransmitted; *++pliCounter = NWRdrStatistics.NcpsTransmitted; pdwCounter = (PDWORD) ++pliCounter; *pdwCounter = NWRdrStatistics.ReadOperations; *++pdwCounter = NWRdrStatistics.RandomReadOperations; *++pdwCounter = NWRdrStatistics.ReadNcps; *++pdwCounter = NWRdrStatistics.WriteOperations; *++pdwCounter = NWRdrStatistics.RandomWriteOperations; *++pdwCounter = NWRdrStatistics.WriteNcps; *++pdwCounter = NWRdrStatistics.Sessions; *++pdwCounter = NWRdrStatistics.Reconnects; *++pdwCounter = NWRdrStatistics.NW2xConnects; *++pdwCounter = NWRdrStatistics.NW3xConnects; *++pdwCounter = NWRdrStatistics.NW4xConnects; *++pdwCounter = NWRdrStatistics.ServerDisconnects;
*++pdwCounter = NWRdrStatistics.PacketBurstReadNcps; *++pdwCounter = NWRdrStatistics.PacketBurstReadTimeouts; *++pdwCounter = NWRdrStatistics.PacketBurstWriteNcps; *++pdwCounter = NWRdrStatistics.PacketBurstWriteTimeouts; *++pdwCounter = NWRdrStatistics.PacketBurstReadNcps + NWRdrStatistics.PacketBurstWriteNcps;
//
// Add an extra empty DWORD to pad the buffer to an 8-byte boundary
//
*++pdwCounter = 0;
*lppData = (LPVOID) ++pdwCounter;
} else {
//
// Failure to access Redirector: clear counters to 0
//
memset(&pPerfCounterBlock[1], 0, SIZE_OF_COUNTER_BLOCK - sizeof(pPerfCounterBlock));
pdwCounter = (PDWORD) ((PBYTE) pPerfCounterBlock + SIZE_OF_COUNTER_BLOCK); *lppData = (LPVOID) pdwCounter;
}
// We sent data for only one Object. (Remember not to confuse this
// with counters. Even if more counters are added, the number of object
// is still only one. However, this does not mean more objects cannot
// be added
*lpNumObjectTypes = 1;
// Fill in the number of bytes we copied - incl. the definitions and the
// counter data.
*lpcbTotalBytes = (DWORD) ((PBYTE) pdwCounter - (PBYTE) pNWDataDefinition);
//
// Make sure the output buffer is 8-byte aligned
//
ASSERT((*lpcbTotalBytes & 0x7) == 0);
return ERROR_SUCCESS; }
/****************************************************************************
FUNCTION: CloseNetWarePerformanceData
Purpose: This routine closes the open handles to NetWare performance counters
Return: ERROR_SUCCESS
****************************************************************************/ DWORD APIENTRY CloseNetWarePerformanceData( ) { if ( hNetWareRdr ) {
NtClose( hNetWareRdr ); hNetWareRdr = NULL; }
return ERROR_SUCCESS;
}
|