921 lines
28 KiB
C
921 lines
28 KiB
C
|
/*++
|
|||
|
|
|||
|
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
|
|||
|
//
|
|||
|
VOID InitializeTheRepSetObjectData(); // Handles the initialization of ReplicaSetDataDefinition
|
|||
|
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
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
FRC_BindTheRpcHandle (
|
|||
|
OUT handle_t *OutHandle
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InitializeTheRepSetObjectData (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes the ReplicaSetDataDefinition data structure.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONG 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 = &ReplicaSetDataDefinition.ReplicaSetObjectType;
|
|||
|
|
|||
|
PerfObject->TotalByteLength = sizeof(REPLICASET_DATA_DEFINITION);
|
|||
|
PerfObject->DefinitionLength = sizeof(REPLICASET_DATA_DEFINITION);
|
|||
|
PerfObject->HeaderLength = sizeof(PERF_OBJECT_TYPE);
|
|||
|
PerfObject->ObjectNameTitleIndex = OBJREPLICASET;
|
|||
|
PerfObject->ObjectNameTitle = 0;
|
|||
|
PerfObject->ObjectHelpTitleIndex = OBJREPLICASET;
|
|||
|
PerfObject->ObjectHelpTitle = 0;
|
|||
|
PerfObject->DetailLevel = PERF_DETAIL_NOVICE;
|
|||
|
PerfObject->NumCounters = FRS_NUMOFCOUNTERS;
|
|||
|
PerfObject->DefaultCounter = 0;
|
|||
|
PerfObject->NumInstances = PERF_NO_INSTANCES;
|
|||
|
PerfObject->CodePage = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Initialization of NumStat (PERF_COUNTER_DEFINITION) structures.
|
|||
|
//
|
|||
|
for (i = 0, j = 2; i < FRS_NUMOFCOUNTERS; i++, j += 2) {
|
|||
|
CounterDef = &ReplicaSetDataDefinition.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 = RepSetInitData[i].counterType;
|
|||
|
CounterDef->CounterSize = RepSetInitData[i].size;
|
|||
|
CounterDef->CounterOffset = RepSetInitData[i].offset +
|
|||
|
SSIZEOFDWORD;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the total size of the counter data types
|
|||
|
//
|
|||
|
SizeOfReplicaSetPerformanceData = SIZEOF_REPSET_COUNTER_DATA +
|
|||
|
SSIZEOFDWORD;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
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;
|
|||
|
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 InitializeCriticalSection in DllMain raised an exception, no point
|
|||
|
// in continuing.
|
|||
|
//
|
|||
|
if (!ShouldPerfmonCollectData) {
|
|||
|
return ERROR_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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. For now, just bail.
|
|||
|
//
|
|||
|
return ERROR_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do the necessary initialization of the PERFMON data structures
|
|||
|
//
|
|||
|
InitializeTheRepSetObjectData();
|
|||
|
|
|||
|
//
|
|||
|
// 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_ALL_ACCESS,
|
|||
|
&hKeyDriverPerf);
|
|||
|
if (WStatus != ERROR_SUCCESS) {
|
|||
|
//
|
|||
|
// Fatal error. No point in continuing.
|
|||
|
// Clean up and exit.
|
|||
|
//
|
|||
|
FilterAndPrintToEventLog(FRS_Op, NTFRSPRF_REGISTRY_ERROR_SET);
|
|||
|
return WStatus;
|
|||
|
}
|
|||
|
|
|||
|
size = sizeof(DWORD);
|
|||
|
WStatus = RegQueryValueEx (hKeyDriverPerf,
|
|||
|
L"First Counter",
|
|||
|
0L,
|
|||
|
&type,
|
|||
|
(LPBYTE)&dwFirstCounter,
|
|||
|
&size);
|
|||
|
if (WStatus != ERROR_SUCCESS || type != REG_DWORD) {
|
|||
|
//
|
|||
|
// Fatal error. No point in continuing. Clean up and exit.
|
|||
|
//
|
|||
|
RegCloseKey (hKeyDriverPerf); // Close the registry key
|
|||
|
FilterAndPrintToEventLog(FRS_Op, NTFRSPRF_REGISTRY_ERROR_SET);
|
|||
|
return WStatus;
|
|||
|
}
|
|||
|
|
|||
|
size = sizeof(DWORD);
|
|||
|
WStatus = RegQueryValueEx (hKeyDriverPerf,
|
|||
|
L"First Help",
|
|||
|
0L,
|
|||
|
&type,
|
|||
|
(LPBYTE)&dwFirstHelp,
|
|||
|
&size);
|
|||
|
if (WStatus != ERROR_SUCCESS || type != REG_DWORD) {
|
|||
|
//
|
|||
|
// Fatal error. No point in continuing. Clean up and exit.
|
|||
|
//
|
|||
|
RegCloseKey (hKeyDriverPerf); // Close the registry key
|
|||
|
FilterAndPrintToEventLog(FRS_Op, NTFRSPRF_REGISTRY_ERROR_SET);
|
|||
|
return WStatus;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey (hKeyDriverPerf); // Close the registry key
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
|
|||
|
//
|
|||
|
// Bind the RPC handle
|
|||
|
//
|
|||
|
if ( (WStatus = FRC_BindTheRpcHandle(&Handle)) != ERROR_SUCCESS) {
|
|||
|
//
|
|||
|
// Fatal Error
|
|||
|
// Free up the memory and return
|
|||
|
//
|
|||
|
FilterAndPrintToEventLog(FRS_Op,
|
|||
|
NTFRSPRF_OPEN_RPC_BINDING_ERROR_SET);
|
|||
|
FreeReplicaSetData();
|
|||
|
return WStatus;
|
|||
|
}
|
|||
|
//
|
|||
|
// (RP)Call the server to set the indices of the instance names
|
|||
|
//
|
|||
|
if ( (WStatus = GetIndicesOfInstancesFromServer(Handle, FRS_datapackage)) != ERROR_SUCCESS) {
|
|||
|
//
|
|||
|
// Fatal Error
|
|||
|
// Free up the memory and return
|
|||
|
//
|
|||
|
FilterAndPrintToEventLog(FRS_Op,
|
|||
|
NTFRSPRF_OPEN_RPC_CALL_ERROR_SET);
|
|||
|
RpcBindingFree(&Handle);
|
|||
|
FreeReplicaSetData();
|
|||
|
return WStatus;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
PERF_COUNTER_BLOCK *pPerfCounterBlock;
|
|||
|
REPLICASET_DATA_DEFINITION *pReplicaSetDataDefinition;
|
|||
|
DWORD dwQueryType;
|
|||
|
LONG j, k;
|
|||
|
PERF_INSTANCE_DEFINITION *p1;
|
|||
|
PWCHAR name;
|
|||
|
|
|||
|
//
|
|||
|
// 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
|
|||
|
//
|
|||
|
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(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
|
|||
|
//
|
|||
|
if (GetCounterDataOfInstancesFromServer(Handle, FRS_collectpakg) != ERROR_SUCCESS) {
|
|||
|
//
|
|||
|
// Fatal error. No point in continuing. Clean up and exit.
|
|||
|
//
|
|||
|
*lpcbTotalBytes = (DWORD)0;
|
|||
|
*lpNumObjectTypes = (DWORD)0;
|
|||
|
RpcBindingFree(&Handle);
|
|||
|
FilterAndPrintToEventLog(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);
|
|||
|
}
|
|||
|
|