summaryrefslogtreecommitdiffstats
path: root/private/nw/perf/nwperf.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/perf/nwperf.c')
-rw-r--r--private/nw/perf/nwperf.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/private/nw/perf/nwperf.c b/private/nw/perf/nwperf.c
new file mode 100644
index 000000000..28d711e54
--- /dev/null
+++ b/private/nw/perf/nwperf.c
@@ -0,0 +1,398 @@
+/****************************************************************************
+
+ 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;
+ RTL_RELATIVE_NAME RelativeName;
+ 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.
+ if ( RtlGetNtProductType( &ProductType))
+ {
+ if ( ProductType != NtProductWinNt )
+ {
+ NWDataDefinition.NWObjectType.ObjectNameTitleIndex = NWCS_GATEWAY_COUNTER_INDEX;
+ NWDataDefinition.NWObjectType.ObjectHelpTitleIndex = NWCS_GATEWAY_HELP_INDEX;
+ }
+ }
+#endif
+
+ hNetWareRdr = NULL;
+
+ RtlInitUnicodeString(&DeviceNameU, DD_NWFS_DEVICE_NAME_U);
+ RelativeName.ContainingDirectory = NULL;
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DeviceNameU,
+ OBJ_CASE_INSENSITIVE,
+ RelativeName.ContainingDirectory,
+ 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;
+
+ *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 = ((PBYTE) pdwCounter - (PBYTE) pNWDataDefinition);
+
+ return ERROR_SUCCESS;
+}
+
+/****************************************************************************
+ FUNCTION: CloseNetWarePerformanceData
+
+ Purpose: This routine closes the open handles to NetWare performance counters
+
+
+ Return: ERROR_SUCCESS
+
+****************************************************************************/
+DWORD APIENTRY
+CloseNetWarePerformanceData(
+)
+{
+ NtClose( hNetWareRdr );
+
+ return ERROR_SUCCESS;
+
+}
+