summaryrefslogtreecommitdiffstats
path: root/private/nw/perf
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/perf')
-rw-r--r--private/nw/perf/makefile6
-rw-r--r--private/nw/perf/nwdata.c296
-rw-r--r--private/nw/perf/nwperf.c398
-rw-r--r--private/nw/perf/nwperf.h144
-rw-r--r--private/nw/perf/nwperf.rc11
-rw-r--r--private/nw/perf/perfnw.def8
-rw-r--r--private/nw/perf/prfutil.c203
-rw-r--r--private/nw/perf/prfutil.h42
-rw-r--r--private/nw/perf/sources46
9 files changed, 1154 insertions, 0 deletions
diff --git a/private/nw/perf/makefile b/private/nw/perf/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/nw/perf/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/nw/perf/nwdata.c b/private/nw/perf/nwdata.c
new file mode 100644
index 000000000..af2b1b8a3
--- /dev/null
+++ b/private/nw/perf/nwdata.c
@@ -0,0 +1,296 @@
+//
+// NWData.c
+//
+// This file contains the initalized Object and counter definition for NetWare
+// redirector performance extensible DLL.
+// This would be the place to add more counters and the change the definitions
+// of the current ones.
+//
+#include "windows.h"
+#include <winperf.h>
+#include "NWPerf.h"
+
+NW_DATA_DEFINITION NWDataDefinition = {
+ { sizeof(NW_DATA_DEFINITION)+
+ SIZE_OF_COUNTER_BLOCK, // Total Bytes ( Size of this header, the counter definitions
+ // and the size of the actual counter data )
+ sizeof(NW_DATA_DEFINITION), // Definition length ( This header and the counter definitions )
+ sizeof(PERF_OBJECT_TYPE), // Header Length ( This header )
+ NWOBJ, // Object Name Title Index
+ 0, // Object Name Title
+ NWOBJ, // Object Help Title Index
+ 0, // Object Help Title
+ PERF_DETAIL_NOVICE, // Detail Level
+ (sizeof(NW_DATA_DEFINITION)-sizeof(PERF_OBJECT_TYPE))/
+ sizeof(PERF_COUNTER_DEFINITION), // Number of Counters
+ 0, // Default Counters
+ 0, // Num Instances
+ 0, // Code Page
+ {0,0}, // Perf Time
+ {0,0} // Perf Freq
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 388,
+ 0,
+ 389,
+ 0,
+ -4,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_BULK_COUNT,
+ sizeof(LARGE_INTEGER),
+ BYTES_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 406,
+ 0,
+ 391,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ IO_OPERATIONS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 400,
+ 0,
+ 401,
+ 0,
+ -1,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_BULK_COUNT,
+ sizeof(LARGE_INTEGER),
+ PACKETS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 264,
+ 0,
+ 265,
+ 0,
+ -4,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_BULK_COUNT,
+ sizeof(LARGE_INTEGER),
+ BYTES_RECEIVED_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 266,
+ 0,
+ 267,
+ 0,
+ -1,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_BULK_COUNT,
+ sizeof(LARGE_INTEGER),
+ NCPS_RECEIVED_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 276,
+ 0,
+ 277,
+ 0,
+ -4,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_BULK_COUNT,
+ sizeof(LARGE_INTEGER),
+ BYTES_TRANSMITTED_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 278,
+ 0,
+ 279,
+ 0,
+ -1,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_BULK_COUNT,
+ sizeof(LARGE_INTEGER),
+ NCPS_TRANSMITTED_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 10,
+ 0,
+ 289,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ RDR_READ_OPERATIONS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 290,
+ 0,
+ 291,
+ 0,
+ -1,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ RANDOM_READ_OPERATIONS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 292,
+ 0,
+ 293,
+ 0,
+ -1,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ READ_NCPS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 12,
+ 0,
+ 299,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ RDR_WRITE_OPERATIONS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 300,
+ 0,
+ 301,
+ 0,
+ -1,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ RANDOM_WRITE_OPERATIONS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 302,
+ 0,
+ 303,
+ 0,
+ -1,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ WRITE_NCPS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 314,
+ 0,
+ 315,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ SESSIONS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 316,
+ 0,
+ 317,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ RECONNECTS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ CONNECT_2X_ID,
+ 0,
+ CONNECT_2X_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ NETWARE_2X_CONNECTS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ CONNECT_3X_ID,
+ 0,
+ CONNECT_3X_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ NETWARE_3X_CONNECTS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ CONNECT_4X_ID,
+ 0,
+ CONNECT_4X_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ NETWARE_4X_CONNECTS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ 326,
+ 0,
+ 327,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ SERVER_DISCONNECTS_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ PACKET_BURST_READ_ID,
+ 0,
+ PACKET_BURST_READ_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ PACKET_BURST_READ_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ PACKET_BURST_READ_TO_ID,
+ 0,
+ PACKET_BURST_READ_TO_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ PACKET_BURST_READ_TO_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ PACKET_BURST_WRITE_ID,
+ 0,
+ PACKET_BURST_WRITE_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ PACKET_BURST_WRITE_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ PACKET_BURST_WRITE_TO_ID,
+ 0,
+ PACKET_BURST_WRITE_TO_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ PACKET_BURST_WRITE_TO_OFFSET
+ },
+ { sizeof(PERF_COUNTER_DEFINITION),
+ PACKET_BURST_IO_ID,
+ 0,
+ PACKET_BURST_IO_ID,
+ 0,
+ 0,
+ PERF_DETAIL_ADVANCED,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ PACKET_BURST_IO_OFFSET
+ }
+};
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;
+
+}
+
diff --git a/private/nw/perf/nwperf.h b/private/nw/perf/nwperf.h
new file mode 100644
index 000000000..f6af9af41
--- /dev/null
+++ b/private/nw/perf/nwperf.h
@@ -0,0 +1,144 @@
+
+//
+// MODULE: NWPerf.H
+//
+// This file contains all the defines and prototypes for the performnce
+// monitoring DLL for NetWare redirector
+//
+// Date: Sept, 28 1993
+
+
+//
+// The routines that load these structures assume that all fields
+// are packed and aligned on DWORD boundries. Alpha support may
+// change this assumption so the pack pragma is used here to insure
+// the DWORD packing assumption remains valid.
+//
+#pragma pack (4)
+
+//
+// All these definitions will have to be updated when new counters are added.
+// if a new counter called COUNTX is added then the Help and Title indicies
+// defines should include a new entry - "#define COUNTXOBJ 4". This increases
+// in increments of 2 because each counter has a title and help index.
+//
+// The Offset of the counters should have another entry - with the size of
+// the data for COUNT -
+// "#define COUNTER_OFFSET_COUNTX COUNTER_OFFSET_USERS+sizeof(COUNTX_TYPE)"
+//
+// The SIZE_OF_COUNTER_BLOCK will be updated to:
+// "#define SIZE_OF_COUNTER_BLOCK COUNTER_OFFSET_COUNTX + sizeof(DWORD)"
+//
+// Finally the NW_DATA_DEFINITION will have a new PERF_COUNTER_DEFINTIION
+// entry
+
+// Title and Help index defines. These are used for looking up the Registry
+// to get at the counter indicies for the title and help strings.
+
+#define NW_NUM_OBJECTS 1
+#define NWOBJ 0
+#define PACKET_BURST_READ_ID 2
+#define PACKET_BURST_READ_TO_ID 4
+#define PACKET_BURST_WRITE_ID 6
+#define PACKET_BURST_WRITE_TO_ID 8
+#define PACKET_BURST_IO_ID 10
+#define CONNECT_2X_ID 12
+#define CONNECT_3X_ID 14
+#define CONNECT_4X_ID 16
+
+//
+// NetWare Redirector data object definitions.
+// The offsets of the counters. The first DWORD is the size of the counter
+// data block. In WinPerf, you will see this as PERF_COUNTER_BLOCK.ByteLength
+//
+#define BYTES_OFFSET sizeof(DWORD)
+#define IO_OPERATIONS_OFFSET BYTES_OFFSET + sizeof(LARGE_INTEGER)
+#define PACKETS_OFFSET IO_OPERATIONS_OFFSET + sizeof(DWORD)
+#define BYTES_RECEIVED_OFFSET PACKETS_OFFSET + \
+ sizeof(LARGE_INTEGER)
+#define NCPS_RECEIVED_OFFSET BYTES_RECEIVED_OFFSET + \
+ sizeof(LARGE_INTEGER)
+#define BYTES_TRANSMITTED_OFFSET \
+ NCPS_RECEIVED_OFFSET + \
+ sizeof(LARGE_INTEGER)
+#define NCPS_TRANSMITTED_OFFSET \
+ BYTES_TRANSMITTED_OFFSET + \
+ sizeof(LARGE_INTEGER)
+#define RDR_READ_OPERATIONS_OFFSET \
+ NCPS_TRANSMITTED_OFFSET + \
+ sizeof(LARGE_INTEGER)
+#define RANDOM_READ_OPERATIONS_OFFSET RDR_READ_OPERATIONS_OFFSET + \
+ sizeof(DWORD)
+#define READ_NCPS_OFFSET RANDOM_READ_OPERATIONS_OFFSET + \
+ sizeof(DWORD)
+#define RDR_WRITE_OPERATIONS_OFFSET READ_NCPS_OFFSET + \
+ sizeof(DWORD)
+#define RANDOM_WRITE_OPERATIONS_OFFSET RDR_WRITE_OPERATIONS_OFFSET + \
+ sizeof(DWORD)
+#define WRITE_NCPS_OFFSET RANDOM_WRITE_OPERATIONS_OFFSET + \
+ sizeof(DWORD)
+#define SESSIONS_OFFSET WRITE_NCPS_OFFSET + \
+ sizeof(DWORD)
+#define RECONNECTS_OFFSET SESSIONS_OFFSET + \
+ sizeof(DWORD)
+#define NETWARE_2X_CONNECTS_OFFSET RECONNECTS_OFFSET + \
+ sizeof(DWORD)
+#define NETWARE_3X_CONNECTS_OFFSET NETWARE_2X_CONNECTS_OFFSET + \
+ sizeof(DWORD)
+#define NETWARE_4X_CONNECTS_OFFSET NETWARE_3X_CONNECTS_OFFSET + \
+ sizeof(DWORD)
+#define SERVER_DISCONNECTS_OFFSET NETWARE_4X_CONNECTS_OFFSET + \
+ sizeof(DWORD)
+#define PACKET_BURST_READ_OFFSET SERVER_DISCONNECTS_OFFSET + \
+ sizeof(DWORD)
+#define PACKET_BURST_READ_TO_OFFSET PACKET_BURST_READ_OFFSET + \
+ sizeof(DWORD)
+#define PACKET_BURST_WRITE_OFFSET PACKET_BURST_READ_TO_OFFSET + \
+ sizeof(DWORD)
+#define PACKET_BURST_WRITE_TO_OFFSET PACKET_BURST_WRITE_OFFSET + \
+ sizeof(DWORD)
+#define PACKET_BURST_IO_OFFSET PACKET_BURST_WRITE_TO_OFFSET + \
+ sizeof(DWORD)
+#define SIZE_OF_COUNTER_BLOCK PACKET_BURST_IO_OFFSET + \
+ sizeof(DWORD)
+
+
+
+
+// The definition of the NetWare Data definition. This structure holds the
+// definition for actual NetWare object and the definition for each of the
+// counters.
+typedef struct _NW_DATA_DEFINITION {
+ PERF_OBJECT_TYPE NWObjectType;
+ PERF_COUNTER_DEFINITION Bytes;
+ PERF_COUNTER_DEFINITION IoOperations;
+ PERF_COUNTER_DEFINITION Ncps;
+ PERF_COUNTER_DEFINITION BytesReceived;
+ PERF_COUNTER_DEFINITION NcpsReceived;
+ PERF_COUNTER_DEFINITION BytesTransmitted;
+ PERF_COUNTER_DEFINITION NcpsTransmitted;
+ PERF_COUNTER_DEFINITION ReadOperations;
+ PERF_COUNTER_DEFINITION RandomReadOperations;
+ PERF_COUNTER_DEFINITION ReadNcps;
+ PERF_COUNTER_DEFINITION WriteOperations;
+ PERF_COUNTER_DEFINITION RandomWriteOperations;
+ PERF_COUNTER_DEFINITION WriteNcps;
+ PERF_COUNTER_DEFINITION Sessions;
+ PERF_COUNTER_DEFINITION Reconnects;
+ PERF_COUNTER_DEFINITION NetWare2XConnects;
+ PERF_COUNTER_DEFINITION NetWare3XConnects;
+ PERF_COUNTER_DEFINITION NetWare4XConnects;
+ PERF_COUNTER_DEFINITION ServerDisconnects;
+ PERF_COUNTER_DEFINITION PacketBurstRead;
+ PERF_COUNTER_DEFINITION PacketBurstReadTimeouts;
+ PERF_COUNTER_DEFINITION PacketBurstWrite;
+ PERF_COUNTER_DEFINITION PacketBurstWriteTimeouts;
+ PERF_COUNTER_DEFINITION PacketBurstIO;
+} NW_DATA_DEFINITION;
+
+#pragma pack ()
+
+PM_OPEN_PROC OpenNetWarePerformanceData;
+PM_COLLECT_PROC CollectNetWarePerformanceData;
+PM_CLOSE_PROC CloseNetWarePerformanceData;
+
diff --git a/private/nw/perf/nwperf.rc b/private/nw/perf/nwperf.rc
new file mode 100644
index 000000000..d9d1eee7e
--- /dev/null
+++ b/private/nw/perf/nwperf.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "Client/Gateway Service for Netware Counters"
+#define VER_INTERNALNAME_STR "PERFNW.DLL"
+#define VER_ORIGINALFILENAME_STR "PERFNW.DLL"
+
+#include "common.ver"
diff --git a/private/nw/perf/perfnw.def b/private/nw/perf/perfnw.def
new file mode 100644
index 000000000..b9884595d
--- /dev/null
+++ b/private/nw/perf/perfnw.def
@@ -0,0 +1,8 @@
+LIBRARY PerfNW
+
+DESCRIPTION 'NetWare(R) Workstation Compatible Service Performance Monitor Support'
+
+EXPORTS
+ OpenNetWarePerformanceData @2
+ CollectNetWarePerformanceData @3
+ CloseNetWarePerformanceData @4
diff --git a/private/nw/perf/prfutil.c b/private/nw/perf/prfutil.c
new file mode 100644
index 000000000..f13286d93
--- /dev/null
+++ b/private/nw/perf/prfutil.c
@@ -0,0 +1,203 @@
+//
+// Prfutil.h
+//
+// Utility procedures from the VGACTRS code in the DDK
+//
+#include "windows.h"
+#include <winperf.h>
+
+#define DEFINE_STRING
+#include "prfutil.h"
+
+DWORD
+GetQueryType (
+ IN LPWSTR lpValue
+)
+/*++
+
+GetQueryType
+
+ returns the type of query described in the lpValue string so that
+ the appropriate processing method may be used
+
+Arguments
+
+ IN lpValue
+ string passed to PerfRegQuery Value for processing
+
+Return Value
+
+ QUERY_GLOBAL
+ if lpValue == 0 (null pointer)
+ lpValue == pointer to Null string
+ lpValue == pointer to "Global" string
+
+ QUERY_FOREIGN
+ if lpValue == pointer to "Foriegn" string
+
+ QUERY_COSTLY
+ if lpValue == pointer to "Costly" string
+
+ otherwise:
+
+ QUERY_ITEMS
+
+--*/
+{
+ TCHAR *pwcArgChar, *pwcTypeChar;
+ BOOL bFound;
+
+ if (lpValue == 0) {
+ return QUERY_GLOBAL;
+ } else if (*lpValue == 0) {
+ return QUERY_GLOBAL;
+ }
+
+ // check for "Global" request
+
+ pwcArgChar = lpValue;
+ pwcTypeChar = GLOBAL_STRING;
+ bFound = TRUE; // assume found until contradicted
+
+ // check to the length of the shortest string
+
+ while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
+ if (*pwcArgChar++ != *pwcTypeChar++) {
+ bFound = FALSE; // no match
+ break; // bail out now
+ }
+ }
+
+ if (bFound) return QUERY_GLOBAL;
+
+ // check for "Foreign" request
+
+ pwcArgChar = lpValue;
+ pwcTypeChar = FOREIGN_STRING;
+ bFound = TRUE; // assume found until contradicted
+
+ // check to the length of the shortest string
+
+ while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
+ if (*pwcArgChar++ != *pwcTypeChar++) {
+ bFound = FALSE; // no match
+ break; // bail out now
+ }
+ }
+
+ if (bFound) return QUERY_FOREIGN;
+
+ // check for "Costly" request
+
+ pwcArgChar = lpValue;
+ pwcTypeChar = COSTLY_STRING;
+ bFound = TRUE; // assume found until contradicted
+
+ // check to the length of the shortest string
+
+ while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
+ if (*pwcArgChar++ != *pwcTypeChar++) {
+ bFound = FALSE; // no match
+ break; // bail out now
+ }
+ }
+
+ if (bFound) return QUERY_COSTLY;
+
+ // if not Global and not Foreign and not Costly,
+ // then it must be an item list
+
+ return QUERY_ITEMS;
+
+}
+
+BOOL
+IsNumberInUnicodeList (
+ IN DWORD dwNumber,
+ IN LPWSTR lpwszUnicodeList
+)
+/*++
+
+IsNumberInUnicodeList
+
+Arguments:
+
+ IN dwNumber
+ DWORD number to find in list
+
+ IN lpwszUnicodeList
+ Null terminated, Space delimited list of decimal numbers
+
+Return Value:
+
+ TRUE:
+ dwNumber was found in the list of unicode number strings
+
+ FALSE:
+ dwNumber was not found in the list.
+
+--*/
+{
+ DWORD dwThisNumber;
+ TCHAR *pwcThisChar;
+ BOOL bValidNumber;
+ BOOL bNewItem;
+ TCHAR wcDelimiter; // could be an argument to be more flexible
+
+ if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
+
+ pwcThisChar = lpwszUnicodeList;
+ dwThisNumber = 0;
+ wcDelimiter = TEXT(' ');
+ bValidNumber = FALSE;
+ bNewItem = TRUE;
+
+ while (TRUE) {
+ switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
+ case DIGIT:
+ // if this is the first digit after a delimiter, then
+ // set flags to start computing the new number
+ if (bNewItem) {
+ bNewItem = FALSE;
+ bValidNumber = TRUE;
+ }
+ if (bValidNumber) {
+ dwThisNumber *= 10;
+ dwThisNumber += (*pwcThisChar - TEXT('0'));
+ }
+ break;
+
+ case DELIMITER:
+ // a delimter is either the delimiter character or the
+ // end of the string ('\0') if when the delimiter has been
+ // reached a valid number was found, then compare it to the
+ // number from the argument list. if this is the end of the
+ // string and no match was found, then return.
+ //
+ if (bValidNumber) {
+ if (dwThisNumber == dwNumber) return TRUE;
+ bValidNumber = FALSE;
+ }
+ if (*pwcThisChar == 0) {
+ return FALSE;
+ } else {
+ bNewItem = TRUE;
+ dwThisNumber = 0;
+ }
+ break;
+
+ case INVALID:
+ // if an invalid character was encountered, ignore all
+ // characters up to the next delimiter and then start fresh.
+ // the invalid number is not compared.
+ bValidNumber = FALSE;
+ break;
+
+ default:
+ break;
+
+ }
+ pwcThisChar++;
+ }
+
+} // IsNumberInUnicodeList
diff --git a/private/nw/perf/prfutil.h b/private/nw/perf/prfutil.h
new file mode 100644
index 000000000..58eb21abd
--- /dev/null
+++ b/private/nw/perf/prfutil.h
@@ -0,0 +1,42 @@
+//
+// Prfutil.h
+//
+// Utility procedures from the VGACTRS code in the DDK
+//
+#ifndef _PRFUTIL_
+#define _PRF_UTIL_
+
+#define QUERY_GLOBAL 1
+#define QUERY_ITEMS 2
+#define QUERY_FOREIGN 3
+#define QUERY_COSTLY 4
+
+#define DIGIT 1
+#define DELIMITER 2
+#define INVALID 3
+
+#define EvalThisChar(c,d) ( \
+ (c == d) ? DELIMITER : \
+ (c == 0) ? DELIMITER : \
+ (c < (WCHAR)'0') ? INVALID : \
+ (c > (WCHAR)'9') ? INVALID : \
+ DIGIT)
+
+BOOL IsNumberInUnicodeList ( IN DWORD dwNumber, IN LPWSTR lpwszUnicodeList );
+DWORD GetQueryType ( IN LPWSTR lpValue );
+
+// only prfutil.c will define GLOBAL_STRING
+#ifdef DEFINE_STRING
+TCHAR GLOBAL_STRING[] = TEXT("Global");
+TCHAR FOREIGN_STRING[] = TEXT("Foreign");
+TCHAR COSTLY_STRING[] = TEXT("Costly");
+TCHAR NULL_STRING[] = TEXT("\0"); // pointer to null string
+#else
+extern TCHAR GLOBAL_STRING[];
+extern TCHAR FOREIGN_STRING[];
+extern TCHAR COSTLY_STRING[];
+extern TCHAR NULL_STRING[];
+#endif
+
+
+#endif // _PRFUTIL_
diff --git a/private/nw/perf/sources b/private/nw/perf/sources
new file mode 100644
index 000000000..4f18ffc64
--- /dev/null
+++ b/private/nw/perf/sources
@@ -0,0 +1,46 @@
+!IF 0
+**************************************************************
+Sources file for building an Win32 dll.
+
+Module Name : Sources for perfnw.dll
+
+Authors: HonWah Chan
+
+Revisions: 09/28/93
+
+INCLUDES= ..\..\..\inc;..\inc
+**************************************************************
+!ENDIF
+
+DLLBASE=0x7500000
+
+MAJORCOMP=sdktools
+MINORCOMP=perfnw
+
+USE_CRTDLL=1
+
+TARGETNAME=perfnw
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DYNLINK
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
+
+
+INCLUDES= ..\inc
+
+SOURCES= \
+ nwperf.c \
+ prfutil.c \
+ nwperf.rc \
+ nwdata.c
+
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
+
+
+
+!IF "$(QFE_BUILD)" != "1"
+NET_C_DEFINES= -DSECURITY -DWIN32 -DSTRICT -DUNICODE -D_UNICODE
+!ELSE
+NET_C_DEFINES= -DSECURITY -DWIN32 -DSTRICT -DUNICODE -D_UNICODE -DQFE_BUILD=1
+!ENDIF