summaryrefslogblamecommitdiffstats
path: root/private/nw/perf/nwperf.c
blob: 28d711e546da5d9de543ed4d93cfa4c9facc5225 (plain) (tree)













































































































































































































































































































































































































                                                                                            
/****************************************************************************

    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;

}