550 lines
14 KiB
C
550 lines
14 KiB
C
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1993 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
perfwins.c
|
|
|
|
This file implements the Extensible Performance Objects for
|
|
the FTP Server service.
|
|
|
|
|
|
FILE HISTORY:
|
|
KeithMo 07-Jun-1993 Created, based on RussBl's sample code.
|
|
|
|
*/
|
|
|
|
|
|
#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 "winsctrs.h"
|
|
#include "perfmsg.h"
|
|
#include "perfutil.h"
|
|
#include "winsintf.h"
|
|
#include "winsdata.h"
|
|
#include "debug.h"
|
|
#include "winsevnt.h"
|
|
|
|
|
|
//
|
|
// Private globals.
|
|
//
|
|
|
|
DWORD cOpens = 0; // Active "opens" reference count.
|
|
BOOL fInitOK = FALSE; // TRUE if DLL initialized OK.
|
|
BOOL sfLogOpen; //indicates whether the log is
|
|
//open or closed
|
|
|
|
BOOL sfErrReported; //to prevent the same error from being
|
|
//logged continuously
|
|
#if DBG
|
|
DWORD WinsdDebug = 0; // Debug behaviour flags.
|
|
#endif // DBG
|
|
|
|
//
|
|
// Public prototypes.
|
|
//
|
|
|
|
PM_OPEN_PROC OpenWinsPerformanceData;
|
|
PM_COLLECT_PROC CollectWinsPerformanceData;
|
|
PM_CLOSE_PROC CloseWinsPerformanceData;
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: OpenWinsPerformanceData
|
|
|
|
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.
|
|
|
|
********************************************************************/
|
|
DWORD OpenWinsPerformanceData( LPWSTR lpDeviceNames )
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
HKEY hkey = NULL;
|
|
// DWORD size;
|
|
// DWORD type;
|
|
DWORD dwFirstCounter;
|
|
DWORD dwFirstHelp;
|
|
|
|
IF_DEBUG( ENTRYPOINTS )
|
|
{
|
|
WINSD_PRINT(( "in OpenWinsPerformanceData\n" ));
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
if( !fInitOK )
|
|
{
|
|
PERF_COUNTER_DEFINITION * pctr;
|
|
DWORD i;
|
|
if(AddSrcToReg() == ERROR_SUCCESS)
|
|
{
|
|
if (!MonOpenEventLog())
|
|
{
|
|
sfLogOpen = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is the *first* open.
|
|
//
|
|
|
|
dwFirstCounter = WINSCTRS_FIRST_COUNTER;
|
|
dwFirstHelp = WINSCTRS_FIRST_HELP;
|
|
|
|
//
|
|
// Update the object & counter name & help indicies.
|
|
//
|
|
|
|
|
|
WinsDataDataDefinition.ObjectType.ObjectNameTitleIndex
|
|
+= dwFirstCounter;
|
|
WinsDataDataDefinition.ObjectType.ObjectHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
|
|
pctr = &WinsDataDataDefinition.UniqueReg;
|
|
|
|
for( i = 0 ; i < NUMBER_OF_WINSDATA_COUNTERS ; i++ )
|
|
{
|
|
pctr->CounterNameTitleIndex += dwFirstCounter;
|
|
pctr->CounterHelpTitleIndex += dwFirstHelp;
|
|
pctr++;
|
|
}
|
|
|
|
//
|
|
// Remember that we initialized OK.
|
|
//
|
|
|
|
fInitOK = TRUE;
|
|
|
|
//
|
|
// Close the registry if we managed to actually open it.
|
|
//
|
|
|
|
if( hkey != NULL )
|
|
{
|
|
RegCloseKey( hkey );
|
|
hkey = NULL;
|
|
}
|
|
|
|
IF_DEBUG( OPEN )
|
|
{
|
|
if( err != NO_ERROR )
|
|
{
|
|
WINSD_PRINT(( "Cannot read registry data, error %lu\n", err ));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bump open counter.
|
|
//
|
|
|
|
if( err == NO_ERROR )
|
|
{
|
|
cOpens++;
|
|
}
|
|
//
|
|
// if sfLogOpen is FALSE, it means that all threads we closed the
|
|
// event log in CloseWinsPerformanceData
|
|
//
|
|
if (!sfLogOpen)
|
|
{
|
|
MonOpenEventLog();
|
|
}
|
|
|
|
return err;
|
|
|
|
} // OpenWinsPerformanceData
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CollectWinsPerformanceData
|
|
|
|
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 CollectWinsPerformanceData( LPWSTR lpValueName,
|
|
LPVOID * lppData,
|
|
LPDWORD lpcbTotalBytes,
|
|
LPDWORD lpNumObjectTypes )
|
|
{
|
|
DWORD dwQueryType;
|
|
ULONG cbRequired;
|
|
DWORD *pdwCounter;
|
|
WINSDATA_COUNTER_BLOCK *pCounterBlock;
|
|
WINSDATA_DATA_DEFINITION *pWinsDataDataDefinition;
|
|
WINSINTF_RESULTS_NEW_T Results;
|
|
#if 0
|
|
WINSINTF_RESULTS_T Results;
|
|
#endif
|
|
WINSINTF_STAT_T *pWinsStats = &Results.WinsStat;
|
|
DWORD Status;
|
|
|
|
|
|
IF_DEBUG( ENTRYPOINTS )
|
|
{
|
|
WINSD_PRINT(( "in CollectWinsPerformanceData\n" ));
|
|
WINSD_PRINT(( " lpValueName = %08lX (%ls)\n",
|
|
lpValueName,
|
|
lpValueName ));
|
|
WINSD_PRINT(( " lppData = %08lX (%08lX)\n",
|
|
lppData,
|
|
*lppData ));
|
|
WINSD_PRINT(( " lpcbTotalBytes = %08lX (%08lX)\n",
|
|
lpcbTotalBytes,
|
|
*lpcbTotalBytes ));
|
|
WINSD_PRINT(( " lpNumObjectTypes = %08lX (%08lX)\n",
|
|
lpNumObjectTypes,
|
|
*lpNumObjectTypes ));
|
|
}
|
|
|
|
//
|
|
// No need to even try if we failed to open...
|
|
//
|
|
|
|
if( !fInitOK )
|
|
{
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "Initialization failed, CollectWinsPerformanceData aborting\n" ));
|
|
}
|
|
|
|
*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 )
|
|
{
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "foreign queries not supported\n" ));
|
|
}
|
|
|
|
//
|
|
// 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(
|
|
WinsDataDataDefinition.ObjectType.ObjectNameTitleIndex,
|
|
lpValueName ) )
|
|
{
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "%ls not a supported object type\n", lpValueName ));
|
|
}
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if there's enough space.
|
|
//
|
|
|
|
pWinsDataDataDefinition = (WINSDATA_DATA_DEFINITION *)*lppData;
|
|
|
|
cbRequired = sizeof(WINSDATA_DATA_DEFINITION) +
|
|
WINSDATA_SIZE_OF_PERFORMANCE_DATA;
|
|
|
|
if( *lpcbTotalBytes < cbRequired )
|
|
{
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "%lu bytes of buffer insufficient, %lu needed\n",
|
|
*lpcbTotalBytes,
|
|
cbRequired ));
|
|
}
|
|
|
|
//
|
|
// Nope.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Copy the (constant, initialized) Object Type and counter definitions
|
|
// to the caller's data buffer
|
|
//
|
|
|
|
memmove( pWinsDataDataDefinition,
|
|
&WinsDataDataDefinition,
|
|
sizeof(WINSDATA_DATA_DEFINITION) );
|
|
|
|
//
|
|
// Try to retrieve the data.
|
|
//
|
|
|
|
Results.WinsStat.NoOfPnrs = 0;
|
|
Results.WinsStat.pRplPnrs = NULL;
|
|
Results.pAddVersMaps = NULL;
|
|
|
|
{
|
|
WINSINTF_BIND_DATA_T BindData;
|
|
handle_t BindHdl;
|
|
|
|
BindData.fTcpIp = FALSE;
|
|
BindData.pPipeName = (LPBYTE)TEXT("\\pipe\\WinsPipe");
|
|
BindData.pServerAdd = (LPBYTE)TEXT("");
|
|
|
|
BindHdl = WinsBind(&BindData);
|
|
Status = WinsStatusNew(BindHdl, WINSINTF_E_STAT, &Results);
|
|
WinsUnbind(&BindData, BindHdl);
|
|
}
|
|
|
|
if( Status != WINSINTF_SUCCESS )
|
|
{
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "cannot retrieve statistics, error %lu\n",
|
|
Status ));
|
|
|
|
}
|
|
|
|
//
|
|
// if we haven't logged the error yet, log it
|
|
//
|
|
if (!sfErrReported)
|
|
{
|
|
REPORT_ERROR(WINS_EVT_WINS_STATUS_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 WINS Server data.
|
|
//
|
|
|
|
pCounterBlock = (WINSDATA_COUNTER_BLOCK *)( pWinsDataDataDefinition + 1 );
|
|
|
|
pCounterBlock->PerfCounterBlock.ByteLength =
|
|
WINSDATA_SIZE_OF_PERFORMANCE_DATA;
|
|
|
|
//
|
|
// Get the pointer to the first (DWORD) counter. This
|
|
// pointer *must* be quadword aligned.
|
|
//
|
|
|
|
pdwCounter = (DWORD *)( pCounterBlock + 1 );
|
|
|
|
WINSD_ASSERT( ( (DWORD_PTR)pdwCounter & 3 ) == 0 );
|
|
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "pWinsDataDataDefinition = %08lX\n", pWinsDataDataDefinition ));
|
|
WINSD_PRINT(( "pCounterBlock = %08lX\n", pCounterBlock ));
|
|
WINSD_PRINT(( "ByteLength = %08lX\n", pCounterBlock->PerfCounterBlock.ByteLength ));
|
|
WINSD_PRINT(( "pliCounter = %08lX\n", pdwCounter ));
|
|
}
|
|
|
|
//
|
|
// Move the DWORDs into the buffer.
|
|
//
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "pdwCounter = %08lX\n", pdwCounter ));
|
|
}
|
|
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfUniqueReg;
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfGroupReg;
|
|
*pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfUniqueReg +
|
|
pWinsStats->Counters.NoOfGroupReg);
|
|
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfUniqueRef;
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfGroupRef;
|
|
*pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfUniqueRef +
|
|
pWinsStats->Counters.NoOfGroupRef);
|
|
*pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfSuccRel +
|
|
pWinsStats->Counters.NoOfFailRel);
|
|
*pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfSuccQueries +
|
|
pWinsStats->Counters.NoOfFailQueries);
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfUniqueCnf;
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfGroupCnf;
|
|
*pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfUniqueCnf +
|
|
pWinsStats->Counters.NoOfGroupCnf);
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfSuccRel;
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfFailRel;
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfSuccQueries;
|
|
*pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfFailQueries;
|
|
|
|
//
|
|
// Update arguments for return.
|
|
//
|
|
|
|
*lppData = (PVOID)pdwCounter;
|
|
*lpNumObjectTypes = 1;
|
|
*lpcbTotalBytes = (DWORD)((BYTE *)pdwCounter - (BYTE *)pWinsDataDataDefinition);
|
|
|
|
IF_DEBUG( COLLECT )
|
|
{
|
|
WINSD_PRINT(( "pData = %08lX\n", *lppData ));
|
|
WINSD_PRINT(( "NumObjectTypes = %08lX\n", *lpNumObjectTypes ));
|
|
WINSD_PRINT(( "cbTotalBytes = %08lX\n", *lpcbTotalBytes ));
|
|
}
|
|
|
|
//
|
|
// Free the API buffer.
|
|
//
|
|
#if 0
|
|
NetApiBufferFree( (LPBYTE)pWinsStats );
|
|
#endif
|
|
|
|
//
|
|
// Free the buffers RPC allocates.
|
|
//
|
|
|
|
WinsFreeMem( Results.pAddVersMaps );
|
|
WinsFreeMem( Results.WinsStat.pRplPnrs );
|
|
|
|
//
|
|
// Success! Honest!!
|
|
//
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CollectWinsPerformanceData
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CloseWinsPerformanceData
|
|
|
|
SYNOPSIS: Terminates the performance counters.
|
|
|
|
RETURNS: DWORD - Win32 status code.
|
|
|
|
HISTORY:
|
|
KeithMo 07-Jun-1993 Created.
|
|
|
|
********************************************************************/
|
|
DWORD CloseWinsPerformanceData( VOID )
|
|
{
|
|
IF_DEBUG( ENTRYPOINTS )
|
|
{
|
|
WINSD_PRINT(( "in CloseWinsPerformanceData\n" ));
|
|
}
|
|
|
|
//
|
|
// No real cleanup to do here.
|
|
//
|
|
|
|
cOpens--;
|
|
|
|
|
|
if (!cOpens)
|
|
{
|
|
//
|
|
// 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;
|
|
}
|
|
return NO_ERROR;
|
|
|
|
} // CloseWinsPerformanceData
|
|
|