You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1045 lines
33 KiB
1045 lines
33 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
perfset.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the functions that implement the PerformanceDLL of the
|
|
REPLICASET Object.
|
|
|
|
Author:
|
|
|
|
Rohan Kumar [rohank] 13-Sept-1998
|
|
|
|
Environment:
|
|
|
|
User Mode Service
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "REPSET.h"
|
|
#include "perfutil.h"
|
|
#include "NTFRSREP.h"
|
|
|
|
//
|
|
// Future Cleanup: Really need a struct to encapsulate this state so the same code
|
|
// can be used for both the replica set and connection perfmon objects
|
|
|
|
//
|
|
// Should Perfmon return Data ? This boolean is set in the DllMain function.
|
|
//
|
|
extern BOOLEAN ShouldPerfmonCollectData;
|
|
|
|
//
|
|
// Data Variable definition
|
|
//
|
|
REPLICASET_DATA_DEFINITION ReplicaSetDataDefinition;
|
|
|
|
//
|
|
// Extern variable definition
|
|
//
|
|
extern ReplicaSetValues RepSetInitData[FRS_NUMOFCOUNTERS];
|
|
|
|
//
|
|
// Sum of counter sizes + SIZEOFDWORD
|
|
//
|
|
DWORD SizeOfReplicaSetPerformanceData = 0;
|
|
|
|
//
|
|
// Number of "Open" threads
|
|
//
|
|
DWORD FRS_dwOpenCount = 0;
|
|
|
|
//
|
|
// Data structure used by the Open RPC Call
|
|
//
|
|
OpenRpcData *FRS_datapackage = NULL;
|
|
|
|
//
|
|
// Data structure used by the Collect RPC Call
|
|
//
|
|
CollectRpcData *FRS_collectpakg = NULL;
|
|
|
|
//
|
|
// Used to filter duplicate eventlog messages.
|
|
//
|
|
BOOLEAN FRS_Op = TRUE, FRS_Cl = TRUE;
|
|
|
|
//
|
|
// Signatures of functions implemented in this file
|
|
//
|
|
|
|
PM_OPEN_PROC OpenReplicaSetPerformanceData; // The Open function
|
|
PM_COLLECT_PROC CollectReplicaSetPerformanceData; // The Collect function
|
|
PM_CLOSE_PROC CloseReplicaSetPerformanceData; // The Close function
|
|
VOID FreeReplicaSetData(); // Frees the allocated memory
|
|
PVOID FRSPerfAlloc(IN DWORD Size); // Allocates memory
|
|
|
|
#undef GET_EXCEPTION_CODE
|
|
#define GET_EXCEPTION_CODE(_x_) \
|
|
{ \
|
|
(_x_) = GetExceptionCode(); \
|
|
if (((LONG)(_x_)) < 0) { \
|
|
(_x_) = FRS_ERR_INTERNAL_API; \
|
|
} \
|
|
/* NTFRSAPI_DBG_PRINT2("Exception caught: %d, 0x%08x\n", (_x_), (_x_)); */ \
|
|
}
|
|
|
|
DWORD
|
|
FRC_BindTheRpcHandle (
|
|
OUT handle_t *OutHandle
|
|
);
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
InitializeObjectData (
|
|
DWORD ObjectLength,
|
|
DWORD ObjectNameTitleIndex,
|
|
DWORD NumCounters,
|
|
PFRS_PERF_DATA_DEFINITION FrsPerfDataDef,
|
|
PFRS_PERF_INIT_VALUES FrsInitValueDef,
|
|
DWORD SizeOfCounterData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the ReplicaSetDataDefinition data structure.
|
|
|
|
Arguments:
|
|
|
|
ObjectLength, - size of Counter Structure returned by the perfmon Object
|
|
ObjectNameTitleIndex, - Index for object Title and help strings.
|
|
NumCounters, - The number of perfmon data counters for the object.
|
|
FrsPerfDataDef, - Counter Structure returned by the perfmon Object
|
|
FrsInitValueDef, - Init structure used to provide counter type, size and offset.
|
|
SizeOfCounterData - The FRS internal struct used to hold the counter data for the object.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns total size of the counter data types.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i, j;
|
|
PPERF_OBJECT_TYPE PerfObject;
|
|
PPERF_COUNTER_DEFINITION CounterDef;
|
|
|
|
//
|
|
// Initialization of ReplicaSetObjectType (PERF_OBJECT_TYPE) field. This structure
|
|
// is defined in the file winperf.h
|
|
//
|
|
PerfObject = &FrsPerfDataDef->ObjectType;
|
|
|
|
PerfObject->TotalByteLength = ObjectLength;
|
|
PerfObject->DefinitionLength = ObjectLength;
|
|
PerfObject->HeaderLength = sizeof(PERF_OBJECT_TYPE);
|
|
PerfObject->ObjectNameTitleIndex = ObjectNameTitleIndex;
|
|
PerfObject->ObjectNameTitle = 0;
|
|
PerfObject->ObjectHelpTitleIndex = ObjectNameTitleIndex;
|
|
PerfObject->ObjectHelpTitle = 0;
|
|
PerfObject->DetailLevel = PERF_DETAIL_NOVICE;
|
|
PerfObject->NumCounters = NumCounters;
|
|
PerfObject->DefaultCounter = 0;
|
|
PerfObject->NumInstances = PERF_NO_INSTANCES;
|
|
PerfObject->CodePage = 0;
|
|
|
|
//
|
|
// Initialization of NumStat (PERF_COUNTER_DEFINITION) structures.
|
|
//
|
|
for (i = 0, j = 2; i < NumCounters; i++, j += 2) {
|
|
CounterDef = &FrsPerfDataDef->NumStat[i];
|
|
|
|
CounterDef->ByteLength = sizeof(PERF_COUNTER_DEFINITION);
|
|
CounterDef->CounterNameTitleIndex = j;
|
|
CounterDef->CounterNameTitle = 0;
|
|
CounterDef->CounterHelpTitleIndex = j;
|
|
CounterDef->CounterHelpTitle = 0;
|
|
CounterDef->DefaultScale = 0;
|
|
CounterDef->DetailLevel = PERF_DETAIL_NOVICE;
|
|
CounterDef->CounterType = FrsInitValueDef[i].counterType;
|
|
CounterDef->CounterSize = FrsInitValueDef[i].size;
|
|
CounterDef->CounterOffset = FrsInitValueDef[i].offset + sizeof(DWORD);
|
|
}
|
|
|
|
//
|
|
// Return the total size of the counter data types
|
|
//
|
|
return SizeOfCounterData + sizeof(DWORD);
|
|
}
|
|
|
|
|
|
|
|
DWORD APIENTRY
|
|
OpenReplicaSetPerformanceData (
|
|
IN LPWSTR lpDeviceNames
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does the following:
|
|
|
|
1. Sets up the data structures (field values of structures used by PERFMON)
|
|
used for collecting the counter data.
|
|
|
|
2. Gets the numerical indices for Instance names from the server using RPC.
|
|
|
|
Arguments:
|
|
|
|
lpDeviceNames - Pointer to the Instance list
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The Initialization was successful OR
|
|
Appropriate DWORD value for the Error status
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG WStatus, tot = 0, i;
|
|
HKEY hKeyDriverPerf = INVALID_HANDLE_VALUE;
|
|
DWORD size, type;
|
|
DWORD dwFirstCounter, dwFirstHelp; // To store the first counter and first help values
|
|
|
|
//
|
|
// Additions for instances
|
|
//
|
|
size_t len;
|
|
PWCHAR p, q;
|
|
INT j, namelen = 0;
|
|
handle_t Handle;
|
|
PPERF_COUNTER_DEFINITION CounterDef;
|
|
|
|
//
|
|
// If InitializeCriticalSectionAndSpinCount returned an error, no point
|
|
// in continuing. Open always has to return success.
|
|
//
|
|
if (!ShouldPerfmonCollectData) {
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Keep track of the number of times open has been called. The Registry
|
|
// routines will limit the access to the initialization routine to only
|
|
// on thread at a time, so synchronization should not be a problem. The
|
|
// FRS_ThrdCounter is used to synchronize between this (Open) and the Close
|
|
// functions.
|
|
//
|
|
EnterCriticalSection(&FRS_ThrdCounter);
|
|
if (FRS_dwOpenCount != 0) {
|
|
//
|
|
// Increment the FRS_dwOpenCount counter which counts the number of
|
|
// times Open has been called.
|
|
//
|
|
FRS_dwOpenCount++;
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
|
|
//
|
|
// Perform some preliminary checks.
|
|
//
|
|
if (FRS_collectpakg != NULL || FRS_datapackage != NULL) {
|
|
//
|
|
// We seem to have failed (in the last call) in the middle of this
|
|
// Open function. Also the open count is zero which means we
|
|
// haven't yet succeeded a open.
|
|
// Free up resources and return.
|
|
//
|
|
FreeReplicaSetData();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Do the necessary initialization of the PERFMON data structures
|
|
//
|
|
SizeOfReplicaSetPerformanceData = InitializeObjectData(
|
|
sizeof(REPLICASET_DATA_DEFINITION),
|
|
OBJREPLICASET,
|
|
FRS_NUMOFCOUNTERS,
|
|
(PFRS_PERF_DATA_DEFINITION) &ReplicaSetDataDefinition,
|
|
(PFRS_PERF_INIT_VALUES) RepSetInitData,
|
|
SIZEOF_REPSET_COUNTER_DATA);
|
|
|
|
WStatus = ERROR_SUCCESS;
|
|
type = REG_DWORD;
|
|
try {
|
|
|
|
//
|
|
// Get the counter and help index base values from the registry. Open key
|
|
// to registry entry, read the First Counter and First Help values. Update
|
|
// the static data structures by adding base to offset value in the structure
|
|
//
|
|
WStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaSet\\Performance",
|
|
0L,
|
|
KEY_READ,
|
|
&hKeyDriverPerf);
|
|
if (WStatus != ERROR_SUCCESS) {
|
|
__leave;
|
|
}
|
|
|
|
size = sizeof(DWORD);
|
|
WStatus = RegQueryValueEx (hKeyDriverPerf,
|
|
L"First Counter",
|
|
0L,
|
|
&type,
|
|
(LPBYTE)&dwFirstCounter,
|
|
&size);
|
|
if (WStatus != ERROR_SUCCESS || type != REG_DWORD) {
|
|
__leave;
|
|
}
|
|
|
|
size = sizeof(DWORD);
|
|
WStatus = RegQueryValueEx (hKeyDriverPerf,
|
|
L"First Help",
|
|
0L,
|
|
&type,
|
|
(LPBYTE)&dwFirstHelp,
|
|
&size);
|
|
if (WStatus != ERROR_SUCCESS || type != REG_DWORD) {
|
|
__leave;
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// Exception
|
|
//
|
|
WStatus = GetExceptionCode();
|
|
}
|
|
|
|
|
|
if (WStatus == ERROR_SUCCESS && type != REG_DWORD) {
|
|
WStatus = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (WStatus != ERROR_SUCCESS) {
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
FRS_REG_CLOSE(hKeyDriverPerf);
|
|
FilterAndPrintToEventLog(WINPERF_LOG_USER, FRS_Op, NTFRSPRF_REGISTRY_ERROR_SET);
|
|
// Open function always returns ERROR_SUCCESS.
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Add the offsets to the name and help fields
|
|
//
|
|
ReplicaSetDataDefinition.ReplicaSetObjectType.ObjectNameTitleIndex += dwFirstCounter;
|
|
ReplicaSetDataDefinition.ReplicaSetObjectType.ObjectHelpTitleIndex += dwFirstHelp;
|
|
|
|
for (i = 0; i < FRS_NUMOFCOUNTERS; i++) {
|
|
CounterDef = &ReplicaSetDataDefinition.NumStat[i];
|
|
CounterDef->CounterNameTitleIndex += dwFirstCounter;
|
|
CounterDef->CounterHelpTitleIndex += dwFirstHelp;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if there are any instances. If there are, parse and set them in a structure
|
|
// to be sent to the server to get the indices for the instance names. These indices
|
|
// are used in the collect function to get the data
|
|
//
|
|
if (lpDeviceNames != NULL) {
|
|
//
|
|
// yes, there are
|
|
//
|
|
q = (PWCHAR) lpDeviceNames;
|
|
//
|
|
// Calculate the number of instances
|
|
//
|
|
while (TRUE) {
|
|
tot++;
|
|
p = wcschr(q, L'\0');
|
|
if (*(p + 1) == L'\0') {
|
|
break;
|
|
}
|
|
q = p + 1;
|
|
}
|
|
|
|
//
|
|
// Bind the RPC handle
|
|
//
|
|
if ( (WStatus = FRC_BindTheRpcHandle(&Handle)) != ERROR_SUCCESS) {
|
|
//
|
|
// Service may be stopped.
|
|
// return success.
|
|
//
|
|
FilterAndPrintToEventLog(WINPERF_LOG_DEBUG, FRS_Op, NTFRSPRF_OPEN_RPC_BINDING_ERROR_SET);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Set the data structure to be sent to the server using RPC
|
|
//
|
|
FRS_datapackage = (OpenRpcData *) FRSPerfAlloc (sizeof(OpenRpcData));
|
|
NTFRS_MALLOC_TEST(FRS_datapackage, FreeReplicaSetData(), FALSE);
|
|
FRS_datapackage->majorver = MAJORVERSION;
|
|
FRS_datapackage->minorver = MINORVERSION;
|
|
FRS_datapackage->ObjectType = REPSET;
|
|
FRS_datapackage->numofinst = tot;
|
|
FRS_datapackage->ver = (PLONG) FRSPerfAlloc (sizeof(LONG));
|
|
NTFRS_MALLOC_TEST(FRS_datapackage->ver, FreeReplicaSetData(), FALSE);
|
|
FRS_datapackage->indices = (inst_index *) FRSPerfAlloc (sizeof(inst_index));
|
|
NTFRS_MALLOC_TEST(FRS_datapackage->indices, FreeReplicaSetData(), FALSE);
|
|
FRS_datapackage->indices->size = tot;
|
|
FRS_datapackage->indices->index = (PLONG) FRSPerfAlloc (FRS_datapackage->numofinst * sizeof(LONG));
|
|
NTFRS_MALLOC_TEST(FRS_datapackage->indices->index, FreeReplicaSetData(), FALSE);
|
|
FRS_datapackage->instnames = (InstanceNames *) FRSPerfAlloc (sizeof(InstanceNames));
|
|
NTFRS_MALLOC_TEST(FRS_datapackage->instnames, FreeReplicaSetData(), FALSE);
|
|
FRS_datapackage->instnames->size = tot;
|
|
FRS_datapackage->instnames->InstanceNames = (inst_name *) FRSPerfAlloc (tot * sizeof(inst_name));
|
|
NTFRS_MALLOC_TEST(FRS_datapackage->instnames->InstanceNames, FreeReplicaSetData(), FALSE);
|
|
//
|
|
// Copy the instance names and set the corresponding size value used by RPC
|
|
//
|
|
q = (PWCHAR) lpDeviceNames;
|
|
for (j = 0; j < FRS_datapackage->numofinst; j++) {
|
|
p = wcschr(q, L'\0');
|
|
len = wcslen (q);
|
|
FRS_datapackage->instnames->InstanceNames[j].size = len + 1;
|
|
FRS_datapackage->instnames->InstanceNames[j].name =
|
|
(PWCHAR) FRSPerfAlloc ((len + 1) * sizeof(WCHAR));
|
|
NTFRS_MALLOC_TEST(FRS_datapackage->instnames->InstanceNames[j].name, FreeReplicaSetData(), FALSE);
|
|
wcscpy(FRS_datapackage->instnames->InstanceNames[j].name, q);
|
|
|
|
//
|
|
// Calculte the total length of all the instance names
|
|
// The extra 1 is for the '\0' character. The names are rounded
|
|
// upto the next 8 byte boundary.
|
|
//
|
|
namelen += (((((len + 1) * sizeof(WCHAR)) + 7) >> 3) << 3);
|
|
q = p + 1;
|
|
}
|
|
|
|
//
|
|
// Set the totalbytelength and NumInstances fields of the PERF_OBJECT_TYPE Data structure,
|
|
// now that we know the number of instances and the length of their names
|
|
//
|
|
ReplicaSetDataDefinition.ReplicaSetObjectType.TotalByteLength +=
|
|
namelen +
|
|
FRS_datapackage->numofinst *
|
|
(SizeOfReplicaSetPerformanceData + SSIZEOFDWORD +
|
|
sizeof(PERF_INSTANCE_DEFINITION));
|
|
|
|
ReplicaSetDataDefinition.ReplicaSetObjectType.NumInstances =
|
|
FRS_datapackage->numofinst;
|
|
|
|
//
|
|
// (RP)Call the server to set the indices of the instance names
|
|
//
|
|
try {
|
|
WStatus = GetIndicesOfInstancesFromServer(Handle, FRS_datapackage);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
GET_EXCEPTION_CODE(WStatus);
|
|
}
|
|
|
|
if (!WIN_SUCCESS(WStatus)) {
|
|
//
|
|
// RPC error trying to contact service.
|
|
// Free up the memory and return success.
|
|
//
|
|
FilterAndPrintToEventLog(WINPERF_LOG_DEBUG, FRS_Op, NTFRSPRF_OPEN_RPC_CALL_ERROR_SET);
|
|
RpcBindingFree(&Handle);
|
|
FreeReplicaSetData();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Set the data structure used by the RPC call in the Collect function
|
|
//
|
|
FRS_collectpakg = (CollectRpcData *) FRSPerfAlloc (sizeof(CollectRpcData));
|
|
NTFRS_MALLOC_TEST(FRS_collectpakg, FreeReplicaSetData(), TRUE);
|
|
FRS_collectpakg->majorver = MAJORVERSION;
|
|
FRS_collectpakg->minorver = MINORVERSION;
|
|
FRS_collectpakg->ObjectType = REPSET;
|
|
FRS_collectpakg->ver = *(FRS_datapackage->ver);
|
|
FRS_collectpakg->numofinst = FRS_datapackage->numofinst;
|
|
FRS_collectpakg->numofcotrs = FRS_NUMOFCOUNTERS;
|
|
FRS_collectpakg->indices = (inst_index *) FRSPerfAlloc (sizeof(inst_index));
|
|
NTFRS_MALLOC_TEST(FRS_collectpakg->indices, FreeReplicaSetData(), TRUE);
|
|
FRS_collectpakg->indices->size = FRS_datapackage->indices->size;
|
|
FRS_collectpakg->indices->index = (PLONG) FRSPerfAlloc (FRS_collectpakg->indices->size * sizeof(LONG));
|
|
NTFRS_MALLOC_TEST(FRS_collectpakg->indices->index, FreeReplicaSetData(), TRUE);
|
|
//
|
|
// Copy the indices got from the server
|
|
//
|
|
for (j = 0; j < FRS_collectpakg->numofinst; j++) {
|
|
FRS_collectpakg->indices->index[j]= FRS_datapackage->indices->index[j];
|
|
}
|
|
//
|
|
// Set the memory blob used to (mem)copy the counter dats from the server
|
|
//
|
|
FRS_collectpakg->databuff = (DataBuffer *) FRSPerfAlloc (sizeof(DataBuffer));
|
|
NTFRS_MALLOC_TEST(FRS_collectpakg->databuff, FreeReplicaSetData(), TRUE);
|
|
FRS_collectpakg->databuff->size = FRS_collectpakg->numofinst *
|
|
SIZEOF_REPSET_COUNTER_DATA;
|
|
|
|
//
|
|
// Allocate memory for the buffer in which the data gets copied.
|
|
//
|
|
FRS_collectpakg->databuff->data = (PBYTE) FRSPerfAlloc (FRS_collectpakg->databuff->size * sizeof(BYTE));
|
|
NTFRS_MALLOC_TEST(FRS_collectpakg->databuff->data, FreeReplicaSetData(), TRUE);
|
|
|
|
RpcBindingFree(&Handle);
|
|
|
|
} else {
|
|
//
|
|
// There are no instances at this time, so set the PERF_OBJECT_TYPE structure fields accordingly
|
|
//
|
|
ReplicaSetDataDefinition.ReplicaSetObjectType.TotalByteLength +=
|
|
SizeOfReplicaSetPerformanceData + SSIZEOFDWORD;
|
|
ReplicaSetDataDefinition.ReplicaSetObjectType.NumInstances =
|
|
PERF_NO_INSTANCES;
|
|
}
|
|
|
|
EnterCriticalSection(&FRS_ThrdCounter);
|
|
FRS_dwOpenCount++; // increment the open counter
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
|
|
FRS_Op = TRUE;
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD APIENTRY
|
|
CollectReplicaSetPerformanceData (
|
|
IN LPWSTR lpValueName,
|
|
IN OUT LPVOID *lppData,
|
|
IN OUT LPDWORD lpcbTotalBytes,
|
|
IN OUT LPDWORD lpNumObjectTypes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine collects the counter data from the server and copies it into
|
|
the callers buffer.
|
|
|
|
Arguments:
|
|
|
|
lpValueName - Wide character string passed by the registry.
|
|
lppData - IN: pointer to the address of the buffer to receive the
|
|
completed PerfDataBlock and the 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.
|
|
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.
|
|
lpNumObjectTypes - 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 buffer pointed by this argument.
|
|
Return Value:
|
|
|
|
ERROR_MORE_DATA - The buffer passed was too small.
|
|
ERROR_SUCCESS - Success or any other error
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Variables for reformatting data to be sent to perfmon
|
|
//
|
|
ULONG SpaceNeeded;
|
|
PBYTE bte, vd;
|
|
PDWORD pdwCounter;
|
|
DWORD dwQueryType;
|
|
LONG j, k;
|
|
PWCHAR name;
|
|
DWORD WStatus;
|
|
LPWSTR lpDeviceNames = NULL;
|
|
HKEY hKeyDriverPerf = INVALID_HANDLE_VALUE;
|
|
DWORD size, type;
|
|
PERF_COUNTER_BLOCK *pPerfCounterBlock;
|
|
|
|
PERF_INSTANCE_DEFINITION *p1;
|
|
REPLICASET_DATA_DEFINITION *pReplicaSetDataDefinition;
|
|
|
|
//
|
|
// RPC Additions
|
|
//
|
|
handle_t Handle;
|
|
|
|
//
|
|
// Check to see that all the pointers that are passed in are fine
|
|
//
|
|
if (lppData == NULL || *lppData == NULL || lpcbTotalBytes == NULL ||
|
|
lpValueName == NULL || lpNumObjectTypes == NULL) {
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Check to see if Open went OK.
|
|
// If not then call then attempt to
|
|
// make the open call here.
|
|
//
|
|
EnterCriticalSection(&FRS_ThrdCounter);
|
|
if (FRS_dwOpenCount == 0) {
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
|
|
try {
|
|
//
|
|
// Get the Export value from the Linkage key
|
|
// SYSTEM\CurrentControlSet\Services\FileReplicaSet\Linkage
|
|
//
|
|
WStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaSet\\Linkage",
|
|
0L,
|
|
KEY_READ,
|
|
&hKeyDriverPerf);
|
|
if (WStatus != ERROR_SUCCESS) {
|
|
__leave;
|
|
}
|
|
|
|
size = 1;
|
|
lpDeviceNames = FRSPerfAlloc(size);
|
|
WStatus = RegQueryValueEx (hKeyDriverPerf,
|
|
L"Export",
|
|
0L,
|
|
&type,
|
|
(LPBYTE)lpDeviceNames,
|
|
&size);
|
|
|
|
if (WStatus == ERROR_MORE_DATA) {
|
|
free(lpDeviceNames);
|
|
lpDeviceNames = FRSPerfAlloc(size);
|
|
if (lpDeviceNames == NULL) {
|
|
WStatus = ERROR_NO_SYSTEM_RESOURCES;
|
|
__leave;
|
|
}
|
|
WStatus = RegQueryValueEx (hKeyDriverPerf,
|
|
L"Export",
|
|
0L,
|
|
&type,
|
|
(LPBYTE)lpDeviceNames,
|
|
&size);
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// Exception
|
|
//
|
|
WStatus = GetExceptionCode();
|
|
}
|
|
|
|
FRS_REG_CLOSE(hKeyDriverPerf);
|
|
|
|
if (WStatus != ERROR_SUCCESS || type != REG_MULTI_SZ) {
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
if (lpDeviceNames != NULL) {
|
|
free(lpDeviceNames);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
if (lpDeviceNames != NULL) {
|
|
WStatus = OpenReplicaSetPerformanceData(lpDeviceNames);
|
|
free(lpDeviceNames);
|
|
}
|
|
} else {
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
}
|
|
|
|
//
|
|
// Check to see if Open went OK.
|
|
//
|
|
EnterCriticalSection(&FRS_ThrdCounter);
|
|
if (FRS_dwOpenCount == 0) {
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
//
|
|
// Fatal error. No point in continuing.
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
|
|
//
|
|
// Check the query type
|
|
//
|
|
dwQueryType = GetQueryType (lpValueName);
|
|
|
|
if (dwQueryType == QUERY_FOREIGN) {
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
if (dwQueryType == QUERY_ITEMS) {
|
|
if ( !(IsNumberInUnicodeList(ReplicaSetDataDefinition.ReplicaSetObjectType
|
|
.ObjectNameTitleIndex, lpValueName)) ) {
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The assumption here is that *lppData is aligned on a 8 byte boundary.
|
|
// If its not, then some object in front of us messed up.
|
|
//
|
|
pReplicaSetDataDefinition = (REPLICASET_DATA_DEFINITION *) *lppData;
|
|
|
|
//
|
|
// Check if the buffer space is sufficient
|
|
//
|
|
SpaceNeeded = (ULONG) ReplicaSetDataDefinition.ReplicaSetObjectType.TotalByteLength;
|
|
|
|
//
|
|
// Check if the buffer space is sufficient
|
|
//
|
|
if ( *lpcbTotalBytes < SpaceNeeded ) {
|
|
//
|
|
// Buffer space is insufficient
|
|
//
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Copy the Object Type and counter definitions to the callers buffer
|
|
//
|
|
memmove (pReplicaSetDataDefinition, &ReplicaSetDataDefinition, sizeof(REPLICASET_DATA_DEFINITION));
|
|
|
|
//
|
|
// Check if the Object has any instances
|
|
//
|
|
if (FRS_datapackage != NULL) {
|
|
|
|
//
|
|
// Bind the RPC handle
|
|
//
|
|
if (FRC_BindTheRpcHandle(&Handle) != ERROR_SUCCESS) {
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
FilterAndPrintToEventLog(WINPERF_LOG_DEBUG, FRS_Cl, NTFRSPRF_COLLECT_RPC_BINDING_ERROR_SET);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Zero the contents of the data buffer.
|
|
//
|
|
ZeroMemory(FRS_collectpakg->databuff->data, FRS_collectpakg->databuff->size);
|
|
|
|
//
|
|
// (RP) Call to get the counter data from the server
|
|
//
|
|
try {
|
|
WStatus = GetCounterDataOfInstancesFromServer(Handle, FRS_collectpakg);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
GET_EXCEPTION_CODE(WStatus);
|
|
}
|
|
|
|
if (!WIN_SUCCESS(WStatus)) {
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
RpcBindingFree(&Handle);
|
|
FilterAndPrintToEventLog(WINPERF_LOG_DEBUG, FRS_Cl, NTFRSPRF_COLLECT_RPC_CALL_ERROR_SET);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
vd = FRS_collectpakg->databuff->data;
|
|
p1 = (PERF_INSTANCE_DEFINITION *)&pReplicaSetDataDefinition[1];
|
|
|
|
//
|
|
// Format the data and copy it into the callers buffer
|
|
//
|
|
for (j = 0; j < FRS_collectpakg->numofinst; j++) {
|
|
DWORD RoundedLen;
|
|
//
|
|
// Name length rounded to the next 8 byte boundary.
|
|
//
|
|
RoundedLen = (((((1 +
|
|
wcslen(FRS_datapackage->instnames->InstanceNames[j].name))
|
|
* sizeof(WCHAR)) + 7) >> 3) << 3) + SSIZEOFDWORD;
|
|
//
|
|
// Set the Instance definition structure
|
|
//
|
|
p1->ByteLength = sizeof (PERF_INSTANCE_DEFINITION) + RoundedLen;
|
|
p1->ParentObjectTitleIndex = 0;
|
|
p1->ParentObjectInstance = 0;
|
|
p1->UniqueID = PERF_NO_UNIQUE_ID;
|
|
p1->NameOffset = sizeof (PERF_INSTANCE_DEFINITION);
|
|
p1->NameLength = (1 +
|
|
wcslen(FRS_datapackage->instnames->InstanceNames[j].name))
|
|
* sizeof(WCHAR);
|
|
//
|
|
// Set the instance name
|
|
//
|
|
name = (PWCHAR) (&p1[1]);
|
|
wcscpy(name, FRS_datapackage->instnames->InstanceNames[j].name);
|
|
//
|
|
// Set the PERF_COUNTER_BLOCK structure
|
|
//
|
|
pPerfCounterBlock = (PERF_COUNTER_BLOCK *)
|
|
(name + (RoundedLen/sizeof(WCHAR)));
|
|
pPerfCounterBlock->ByteLength = SizeOfReplicaSetPerformanceData;
|
|
//
|
|
// Finally set the counter data
|
|
//
|
|
bte = ((PBYTE) (&pPerfCounterBlock[1]));
|
|
CopyMemory (bte, vd, SIZEOF_REPSET_COUNTER_DATA);
|
|
vd += SIZEOF_REPSET_COUNTER_DATA;
|
|
bte += SIZEOF_REPSET_COUNTER_DATA;
|
|
p1 = (PERF_INSTANCE_DEFINITION *) bte;
|
|
}
|
|
//
|
|
// Update the arguments for return
|
|
//
|
|
*lpNumObjectTypes = REPLICASET_NUM_PERF_OBJECT_TYPES;
|
|
*lppData = (PVOID) p1;
|
|
//
|
|
// Set the totalbytes being returned.
|
|
//
|
|
*lpcbTotalBytes = (DWORD)((PBYTE) p1 - (PBYTE) pReplicaSetDataDefinition);
|
|
RpcBindingFree(&Handle);
|
|
FRS_Cl = TRUE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
else {
|
|
//
|
|
// No instances as of now, so fill zeros for the counter data
|
|
//
|
|
pPerfCounterBlock = (PERF_COUNTER_BLOCK *)
|
|
(((PBYTE)&pReplicaSetDataDefinition[1]) +
|
|
SSIZEOFDWORD);
|
|
pPerfCounterBlock->ByteLength = SizeOfReplicaSetPerformanceData;
|
|
bte = ((PBYTE) (&pPerfCounterBlock[1]));
|
|
ZeroMemory (bte, SIZEOF_REPSET_COUNTER_DATA);
|
|
bte += SIZEOF_REPSET_COUNTER_DATA;
|
|
*lppData = (PVOID) bte;
|
|
*lpNumObjectTypes = REPLICASET_NUM_PERF_OBJECT_TYPES;
|
|
*lpcbTotalBytes =
|
|
(DWORD)((PBYTE) bte - (PBYTE) pReplicaSetDataDefinition);
|
|
FRS_Cl = TRUE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DWORD APIENTRY
|
|
CloseReplicaSetPerformanceData (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the open count and frees up the memory allocated by
|
|
the Open and Collect routines if needed.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
|
|
{
|
|
EnterCriticalSection(&FRS_ThrdCounter);
|
|
//
|
|
// Check to see if the open count is zero. This should never happen but
|
|
// just in case.
|
|
//
|
|
if (FRS_dwOpenCount == 0) {
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
//
|
|
// Decrement the Open count.
|
|
//
|
|
FRS_dwOpenCount--;
|
|
//
|
|
// If the open count becomes zero, free up the memory since no more threads
|
|
// are going to collect data.
|
|
//
|
|
if (FRS_dwOpenCount == 0) {
|
|
//
|
|
// Call the routine that frees up the memory.
|
|
//
|
|
FreeReplicaSetData();
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
} else {
|
|
LeaveCriticalSection(&FRS_ThrdCounter);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeReplicaSetData(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees up the memory allocated by the Open and Collect routines.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
LONG j;
|
|
|
|
//
|
|
// Free up the Datapackage strucutre.
|
|
//
|
|
if (FRS_datapackage != NULL) {
|
|
if (FRS_datapackage->ver != NULL) {
|
|
free(FRS_datapackage->ver);
|
|
}
|
|
if (FRS_datapackage->indices != NULL) {
|
|
if (FRS_datapackage->indices->index != NULL) {
|
|
free(FRS_datapackage->indices->index);
|
|
}
|
|
free(FRS_datapackage->indices);
|
|
}
|
|
if (FRS_datapackage->instnames != NULL) {
|
|
if (FRS_datapackage->instnames->InstanceNames != NULL) {
|
|
for (j = 0; j < FRS_datapackage->numofinst; j++) {
|
|
if (FRS_datapackage->instnames->InstanceNames[j].name != NULL) {
|
|
free(FRS_datapackage->instnames->InstanceNames[j].name);
|
|
}
|
|
}
|
|
free(FRS_datapackage->instnames->InstanceNames);
|
|
}
|
|
free(FRS_datapackage->instnames);
|
|
}
|
|
free(FRS_datapackage);
|
|
FRS_datapackage = NULL;
|
|
}
|
|
|
|
//
|
|
// Free up the collect package structure.
|
|
//
|
|
if (FRS_collectpakg != NULL) {
|
|
if (FRS_collectpakg->indices != NULL) {
|
|
if (FRS_collectpakg->indices->index != NULL) {
|
|
free(FRS_collectpakg->indices->index);
|
|
}
|
|
free(FRS_collectpakg->indices);
|
|
}
|
|
if (FRS_collectpakg->databuff != NULL) {
|
|
if (FRS_collectpakg->databuff->data != NULL) {
|
|
free(FRS_collectpakg->databuff->data);
|
|
}
|
|
free(FRS_collectpakg->databuff);
|
|
}
|
|
free(FRS_collectpakg);
|
|
FRS_collectpakg = NULL;
|
|
}
|
|
}
|
|
|
|
PVOID
|
|
FRSPerfAlloc(
|
|
IN DWORD Size
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Allocate memory and fill it with zeros before returning the pointer.
|
|
|
|
Arguments:
|
|
|
|
Size - Size of the memory request in bytes.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the allocated memory or NULL if memory wasn't available.
|
|
--*/
|
|
{
|
|
PVOID Node;
|
|
|
|
if (Size == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
Node = (PVOID) malloc (Size);
|
|
if (Node == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ZeroMemory(Node, Size);
|
|
return Node;
|
|
}
|
|
|
|
//
|
|
// Functions (for memory handling) used by the client stub
|
|
//
|
|
void *
|
|
midl_user_allocate
|
|
(
|
|
size
|
|
)
|
|
size_t size;
|
|
{
|
|
unsigned char *ptr;
|
|
ptr = malloc (size);
|
|
return ( (void *)ptr );
|
|
}
|
|
|
|
void
|
|
midl_user_free
|
|
(
|
|
object
|
|
)
|
|
void * object;
|
|
{
|
|
free (object);
|
|
}
|
|
|