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.
1075 lines
35 KiB
1075 lines
35 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
perfconn.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the (three) functions that implement the PerformanceDLL of the
|
|
REPLICACONN Object.
|
|
|
|
Author:
|
|
|
|
Rohan Kumar [rohank] 13-Sept-1998
|
|
|
|
Environment:
|
|
|
|
User Mode Service
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "REPCONN.h"
|
|
#include "perfutil.h"
|
|
#include "NTFRSCON.h"
|
|
|
|
//
|
|
// Should Perfmon return Data ? This boolean is set in the DllMain function.
|
|
//
|
|
extern BOOLEAN ShouldPerfmonCollectData;
|
|
|
|
//
|
|
// Data Variable definition
|
|
//
|
|
REPLICACONN_DATA_DEFINITION ReplicaConnDataDefinition;
|
|
|
|
//
|
|
// Extern variable definition
|
|
//
|
|
extern ReplicaConnValues RepConnInitData[FRC_NUMOFCOUNTERS];
|
|
|
|
//
|
|
// Sum of counter sizes + SIZEOFDWORD
|
|
//
|
|
DWORD SizeOfReplicaConnPerformanceData = 0;
|
|
|
|
//
|
|
// Number of "Open" threads
|
|
//
|
|
DWORD FRC_dwOpenCount = 0;
|
|
|
|
//
|
|
// Data structure used by the Open RPC Call
|
|
//
|
|
OpenRpcData *FRC_datapackage = NULL;
|
|
|
|
//
|
|
// Data structure used by the Collect RPC Call
|
|
//
|
|
CollectRpcData *FRC_collectpakg = NULL;
|
|
|
|
//
|
|
// Used to filter duplicate eventlog messages.
|
|
//
|
|
BOOLEAN FRC_Op = TRUE, FRC_Cl = TRUE;
|
|
|
|
//
|
|
// Signatures of functions implemented in this file
|
|
//
|
|
|
|
PM_OPEN_PROC OpenReplicaConnPerformanceData; // The Open function
|
|
PM_COLLECT_PROC CollectReplicaConnPerformanceData; // The Collect function
|
|
PM_CLOSE_PROC CloseReplicaConnPerformanceData; // The Close function
|
|
|
|
DWORD FRC_BindTheRpcHandle(handle_t *); // Binds the RPC handle
|
|
VOID FreeReplicaConnData(); // Free 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_)); */ \
|
|
}
|
|
|
|
|
|
#if 0
|
|
VOID
|
|
InitializeTheRepConnObjectData(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the ReplicaConnDataDefinition data structure
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG i, j;
|
|
PPERF_OBJECT_TYPE PerfObject;
|
|
PPERF_COUNTER_DEFINITION CounterDef;
|
|
|
|
//
|
|
// Initialization of ReplicaConnObjectType (PERF_OBJECT_TYPE) field.
|
|
//
|
|
PerfObject = &ReplicaConnDataDefinition.ReplicaConnObjectType;
|
|
|
|
PerfObject->TotalByteLength = sizeof(REPLICACONN_DATA_DEFINITION);
|
|
PerfObject->DefinitionLength = sizeof(REPLICACONN_DATA_DEFINITION);
|
|
PerfObject->HeaderLength = sizeof(PERF_OBJECT_TYPE);
|
|
PerfObject->ObjectNameTitleIndex = OBJREPLICACONN;
|
|
PerfObject->ObjectNameTitle = 0;
|
|
PerfObject->ObjectHelpTitleIndex = OBJREPLICACONN;
|
|
PerfObject->ObjectHelpTitle = 0;
|
|
PerfObject->DetailLevel = PERF_DETAIL_NOVICE;
|
|
PerfObject->NumCounters = FRC_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 < FRC_NUMOFCOUNTERS; i++, j += 2) {
|
|
CounterDef = &ReplicaConnDataDefinition.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 = RepConnInitData[i].counterType;
|
|
CounterDef->CounterSize = RepConnInitData[i].size;
|
|
CounterDef->CounterOffset = RepConnInitData[i].offset + sizeof(DWORD);
|
|
}
|
|
|
|
//
|
|
// Set the total size of the counter data types
|
|
//
|
|
SizeOfReplicaConnPerformanceData = SIZEOF_REPCONN_COUNTER_DATA +
|
|
CSIZEOFDWORD;
|
|
}
|
|
#endif
|
|
|
|
|
|
DWORD APIENTRY
|
|
OpenReplicaConnPerformanceData (
|
|
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, WStatus1, i;
|
|
HKEY hKeyDriverPerf = INVALID_HANDLE_VALUE;
|
|
DWORD size, type;
|
|
DWORD dwFirstCounter, dwFirstHelp;
|
|
//
|
|
// Additions for instances
|
|
//
|
|
size_t len, tot = 0;
|
|
PWCHAR p, q;
|
|
INT j, namelen = 0;
|
|
handle_t Handle;
|
|
PPERF_COUNTER_DEFINITION CounterDef;
|
|
|
|
//
|
|
// If InitializeCriticalSectionAndSpinCount returned 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
|
|
// FRC_ThrdCounter is used to synchronize between this (Open) and the Close
|
|
// functions.
|
|
//
|
|
EnterCriticalSection(&FRC_ThrdCounter);
|
|
if (FRC_dwOpenCount != 0) {
|
|
//
|
|
// Increment the FRC_dwOpenCount counter which counts the number of
|
|
// times Open has been called.
|
|
//
|
|
FRC_dwOpenCount++;
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
|
|
//
|
|
// Perform some preliminary checks.
|
|
//
|
|
if (FRC_collectpakg != NULL || FRC_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.
|
|
//
|
|
FreeReplicaConnData();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Do the necessary initialization of the PERFMON data structures
|
|
//
|
|
SizeOfReplicaConnPerformanceData = InitializeObjectData(
|
|
sizeof(REPLICACONN_DATA_DEFINITION),
|
|
OBJREPLICACONN,
|
|
FRC_NUMOFCOUNTERS,
|
|
(PFRS_PERF_DATA_DEFINITION) &ReplicaConnDataDefinition,
|
|
(PFRS_PERF_INIT_VALUES) RepConnInitData,
|
|
SIZEOF_REPCONN_COUNTER_DATA);
|
|
|
|
//
|
|
// 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\\FileReplicaConn\\Performance",
|
|
0L,
|
|
KEY_READ,
|
|
&hKeyDriverPerf);
|
|
if (WStatus != ERROR_SUCCESS) {
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
FilterAndPrintToEventLog(WINPERF_LOG_USER, FRC_Op, NTFRSPRF_REGISTRY_ERROR_CONN);
|
|
// Open function always returns ERROR_SUCCESS.
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
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.
|
|
//
|
|
FRS_REG_CLOSE(hKeyDriverPerf); // Close the registry key
|
|
FilterAndPrintToEventLog(WINPERF_LOG_USER, FRC_Op, NTFRSPRF_REGISTRY_ERROR_CONN);
|
|
// Open function always returns ERROR_SUCCESS.
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
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.
|
|
//
|
|
FRS_REG_CLOSE(hKeyDriverPerf); // Close the registry key
|
|
FilterAndPrintToEventLog(WINPERF_LOG_USER, FRC_Op, NTFRSPRF_REGISTRY_ERROR_CONN);
|
|
// Open function always returns ERROR_SUCCESS.
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Add offsets to the name and help fields
|
|
//
|
|
ReplicaConnDataDefinition.ReplicaConnObjectType.ObjectNameTitleIndex += dwFirstCounter;
|
|
ReplicaConnDataDefinition.ReplicaConnObjectType.ObjectHelpTitleIndex += dwFirstHelp;
|
|
|
|
for (i = 0; i < FRC_NUMOFCOUNTERS; i++) {
|
|
CounterDef = &ReplicaConnDataDefinition.NumStat[i];
|
|
CounterDef->CounterNameTitleIndex += dwFirstCounter;
|
|
CounterDef->CounterHelpTitleIndex += dwFirstHelp;
|
|
}
|
|
|
|
FRS_REG_CLOSE(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;
|
|
}
|
|
|
|
//
|
|
// Bind the RPC handle
|
|
//
|
|
if ( (WStatus = FRC_BindTheRpcHandle(&Handle)) != ERROR_SUCCESS) {
|
|
//
|
|
// Service may be stopped.
|
|
// return success.
|
|
//
|
|
FilterAndPrintToEventLog(WINPERF_LOG_DEBUG, FRC_Op, NTFRSPRF_OPEN_RPC_BINDING_ERROR_CONN);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Set the data structure to be sent to the server using RPC
|
|
//
|
|
FRC_datapackage = (OpenRpcData *) FRSPerfAlloc (sizeof(OpenRpcData));
|
|
NTFRS_MALLOC_TEST(FRC_datapackage, FreeReplicaConnData(), FALSE);
|
|
FRC_datapackage->majorver = MAJORVERSION;
|
|
FRC_datapackage->minorver = MINORVERSION;
|
|
FRC_datapackage->ObjectType = REPCONN;
|
|
FRC_datapackage->numofinst = tot;
|
|
FRC_datapackage->ver = (PLONG) FRSPerfAlloc (sizeof(LONG));
|
|
NTFRS_MALLOC_TEST(FRC_datapackage->ver, FreeReplicaConnData(), FALSE);
|
|
FRC_datapackage->indices = (inst_index *) FRSPerfAlloc (sizeof(inst_index));
|
|
NTFRS_MALLOC_TEST(FRC_datapackage->indices, FreeReplicaConnData(), FALSE);
|
|
FRC_datapackage->indices->size = tot;
|
|
FRC_datapackage->indices->index = (PLONG) FRSPerfAlloc ( FRC_datapackage->numofinst * sizeof(LONG));
|
|
NTFRS_MALLOC_TEST(FRC_datapackage->indices->index, FreeReplicaConnData(), FALSE);
|
|
FRC_datapackage->instnames = (InstanceNames *) FRSPerfAlloc (sizeof(InstanceNames));
|
|
NTFRS_MALLOC_TEST(FRC_datapackage->instnames, FreeReplicaConnData(), FALSE);
|
|
FRC_datapackage->instnames->size = tot;
|
|
FRC_datapackage->instnames->InstanceNames = (inst_name *) FRSPerfAlloc (tot * sizeof(inst_name));
|
|
NTFRS_MALLOC_TEST(FRC_datapackage->instnames->InstanceNames, FreeReplicaConnData(), FALSE);
|
|
//
|
|
// Copy the instance names and set the corresponding size value used by RPC
|
|
//
|
|
q = (PWCHAR) lpDeviceNames;
|
|
for (j = 0; j < FRC_datapackage->numofinst; j++) {
|
|
p = wcschr(q, L'\0');
|
|
len = wcslen (q);
|
|
FRC_datapackage->instnames->InstanceNames[j].size = len + 1;
|
|
FRC_datapackage->instnames->InstanceNames[j].name =
|
|
(PWCHAR) FRSPerfAlloc ((len + 1) * sizeof(WCHAR));
|
|
NTFRS_MALLOC_TEST(FRC_datapackage->instnames->InstanceNames[j].name, FreeReplicaConnData(), FALSE);
|
|
wcscpy(FRC_datapackage->instnames->InstanceNames[j].name, q);
|
|
//
|
|
// Calculate the total length of all the instance names
|
|
// The extra 1 is for the '\0' character. The namelen is
|
|
// 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
|
|
//
|
|
ReplicaConnDataDefinition.ReplicaConnObjectType.TotalByteLength +=
|
|
namelen +
|
|
(FRC_datapackage->numofinst *
|
|
(SizeOfReplicaConnPerformanceData + CSIZEOFDWORD +
|
|
sizeof(PERF_INSTANCE_DEFINITION)));
|
|
|
|
ReplicaConnDataDefinition.ReplicaConnObjectType.NumInstances =
|
|
FRC_datapackage->numofinst;
|
|
|
|
//
|
|
// Call the server to set the indices of the instance names
|
|
//
|
|
try {
|
|
WStatus = GetIndicesOfInstancesFromServer(Handle, FRC_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, FRC_Op, NTFRSPRF_OPEN_RPC_CALL_ERROR_CONN);
|
|
WStatus1 = RpcBindingFree(&Handle);
|
|
FreeReplicaConnData();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Set the data structure used by the RPC call in the Collect function
|
|
//
|
|
FRC_collectpakg = (CollectRpcData *) FRSPerfAlloc (sizeof(CollectRpcData));
|
|
NTFRS_MALLOC_TEST(FRC_collectpakg, FreeReplicaConnData(), TRUE);
|
|
FRC_collectpakg->majorver = MAJORVERSION;
|
|
FRC_collectpakg->minorver = MINORVERSION;
|
|
FRC_collectpakg->ObjectType = REPCONN;
|
|
FRC_collectpakg->ver = *(FRC_datapackage->ver);
|
|
FRC_collectpakg->numofinst = FRC_datapackage->numofinst;
|
|
FRC_collectpakg->numofcotrs = FRC_NUMOFCOUNTERS;
|
|
FRC_collectpakg->indices = (inst_index *) FRSPerfAlloc (sizeof(inst_index));
|
|
NTFRS_MALLOC_TEST(FRC_collectpakg->indices, FreeReplicaConnData(), TRUE);
|
|
FRC_collectpakg->indices->size = FRC_datapackage->indices->size;
|
|
FRC_collectpakg->indices->index = (PLONG) FRSPerfAlloc (FRC_collectpakg->indices->size * sizeof(LONG));
|
|
NTFRS_MALLOC_TEST(FRC_collectpakg->indices->index, FreeReplicaConnData(), TRUE);
|
|
//
|
|
// Copy the indices got from the server
|
|
//
|
|
for (j = 0; j < FRC_collectpakg->numofinst; j++) {
|
|
FRC_collectpakg->indices->index[j]= FRC_datapackage->indices->index[j];
|
|
}
|
|
//
|
|
// Set the memory blob used to (mem)copy the counter dats from the server
|
|
//
|
|
FRC_collectpakg->databuff = (DataBuffer *) FRSPerfAlloc (sizeof(DataBuffer));
|
|
NTFRS_MALLOC_TEST(FRC_collectpakg->databuff, FreeReplicaConnData(), TRUE);
|
|
FRC_collectpakg->databuff->size = FRC_collectpakg->numofinst *
|
|
SIZEOF_REPCONN_COUNTER_DATA;
|
|
|
|
//
|
|
// Allocate memory for the buffer in which the data gets copied.
|
|
//
|
|
FRC_collectpakg->databuff->data = (PBYTE) FRSPerfAlloc (FRC_collectpakg->databuff->size * sizeof(BYTE));
|
|
NTFRS_MALLOC_TEST(FRC_collectpakg->databuff->data, FreeReplicaConnData(), TRUE);
|
|
|
|
WStatus1 = RpcBindingFree(&Handle);
|
|
|
|
} else {
|
|
//
|
|
// There are no instances at this time, so set the PERF_OBJECT_TYPE structure fields accordingly
|
|
//
|
|
ReplicaConnDataDefinition.ReplicaConnObjectType.TotalByteLength +=
|
|
SizeOfReplicaConnPerformanceData + CSIZEOFDWORD;
|
|
ReplicaConnDataDefinition.ReplicaConnObjectType.NumInstances =
|
|
PERF_NO_INSTANCES;
|
|
}
|
|
|
|
EnterCriticalSection(&FRC_ThrdCounter);
|
|
FRC_dwOpenCount++; // increment the open counter
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
|
|
FRC_Op = TRUE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
DWORD APIENTRY
|
|
CollectReplicaConnPerformanceData (
|
|
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
|
|
//
|
|
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;
|
|
REPLICACONN_DATA_DEFINITION *pReplicaConnDataDefinition;
|
|
|
|
//
|
|
// 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(&FRC_ThrdCounter);
|
|
if (FRC_dwOpenCount == 0) {
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
|
|
try {
|
|
//
|
|
// Get the Export value from the Linkage key
|
|
// SYSTEM\CurrentControlSet\Services\FileReplicaConn\Linkage
|
|
//
|
|
WStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaConn\\Linkage",
|
|
0L,
|
|
KEY_READ,
|
|
&hKeyDriverPerf);
|
|
if (WStatus != ERROR_SUCCESS) {
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Start with string length MAX_PATH and increase
|
|
// if required. If lpDeviceNames is NULL for the
|
|
// first call then the function succeeds without
|
|
// returning a value.
|
|
//
|
|
size = MAX_PATH * sizeof(WCHAR);
|
|
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 = OpenReplicaConnPerformanceData(lpDeviceNames);
|
|
free(lpDeviceNames);
|
|
}
|
|
} else {
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
}
|
|
|
|
//
|
|
// Check to see if Open went OK
|
|
//
|
|
EnterCriticalSection(&FRC_ThrdCounter);
|
|
if (FRC_dwOpenCount == 0) {
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
//
|
|
// Fatal error. No point in continuing.
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
LeaveCriticalSection(&FRC_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(
|
|
ReplicaConnDataDefinition.ReplicaConnObjectType
|
|
.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.
|
|
//
|
|
pReplicaConnDataDefinition = (REPLICACONN_DATA_DEFINITION *) *lppData;
|
|
|
|
//
|
|
// Check if the buffer space is sufficient
|
|
//
|
|
SpaceNeeded = (ULONG) ReplicaConnDataDefinition.ReplicaConnObjectType.TotalByteLength;
|
|
|
|
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 (pReplicaConnDataDefinition,
|
|
&ReplicaConnDataDefinition,
|
|
sizeof(REPLICACONN_DATA_DEFINITION));
|
|
|
|
//
|
|
// Check if the Object has any instances
|
|
//
|
|
if (FRC_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, FRC_Cl, NTFRSPRF_COLLECT_RPC_BINDING_ERROR_CONN);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Zero the contents of the data buffer.
|
|
//
|
|
ZeroMemory(FRC_collectpakg->databuff->data, FRC_collectpakg->databuff->size);
|
|
|
|
//
|
|
// Get the counter data from the server
|
|
//
|
|
try {
|
|
WStatus = GetCounterDataOfInstancesFromServer(Handle, FRC_collectpakg);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
GET_EXCEPTION_CODE(WStatus);
|
|
}
|
|
if (!WIN_SUCCESS(WStatus)) {
|
|
//
|
|
// Fatal error. No point in continuing. Clean up and exit.
|
|
//
|
|
WStatus = RpcBindingFree(&Handle);
|
|
*lpcbTotalBytes = (DWORD)0;
|
|
*lpNumObjectTypes = (DWORD)0;
|
|
FilterAndPrintToEventLog(WINPERF_LOG_DEBUG, FRC_Cl, NTFRSPRF_COLLECT_RPC_CALL_ERROR_CONN);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
vd = FRC_collectpakg->databuff->data;
|
|
p1 = (PERF_INSTANCE_DEFINITION *)&pReplicaConnDataDefinition[1];
|
|
|
|
//
|
|
// Format the data and copy it into the callers buffer
|
|
//
|
|
for (j = 0; j < FRC_collectpakg->numofinst; j++) {
|
|
DWORD RoundedLen;
|
|
//
|
|
// Name length rounded to the next 8 byte boundary.
|
|
//
|
|
RoundedLen = (((((1 +
|
|
wcslen(FRC_datapackage->instnames->InstanceNames[j].name))
|
|
* sizeof(WCHAR)) + 7) >> 3) << 3) + CSIZEOFDWORD;
|
|
//
|
|
// 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(FRC_datapackage->instnames->InstanceNames[j].name))
|
|
* sizeof(WCHAR);
|
|
//
|
|
// Set the instance name
|
|
//
|
|
name = (PWCHAR) (&p1[1]);
|
|
wcscpy(name, FRC_datapackage->instnames->InstanceNames[j].name);
|
|
//
|
|
// Set the PERF_COUNTER_BLOCK structure
|
|
//
|
|
pPerfCounterBlock = (PERF_COUNTER_BLOCK *)
|
|
(name + (RoundedLen/sizeof(WCHAR)));
|
|
pPerfCounterBlock->ByteLength = SizeOfReplicaConnPerformanceData;
|
|
//
|
|
// Finally set the counter data. Pad 8 bytes to have 8 byte
|
|
// alignment.
|
|
//
|
|
bte = ((PBYTE) (&pPerfCounterBlock[1]));
|
|
CopyMemory (bte, vd, SIZEOF_REPCONN_COUNTER_DATA);
|
|
vd += SIZEOF_REPCONN_COUNTER_DATA;
|
|
bte += SIZEOF_REPCONN_COUNTER_DATA;
|
|
p1 = (PERF_INSTANCE_DEFINITION *) bte;
|
|
}
|
|
//
|
|
// Update the arguments for return
|
|
//
|
|
*lpNumObjectTypes = REPLICACONN_NUM_PERF_OBJECT_TYPES;
|
|
*lppData = (PVOID) p1;
|
|
//
|
|
// Set the totalbytes being returned.
|
|
//
|
|
*lpcbTotalBytes = (DWORD)((PBYTE) p1 - (PBYTE) pReplicaConnDataDefinition);
|
|
WStatus = RpcBindingFree(&Handle);
|
|
FRC_Cl = TRUE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
else {
|
|
//
|
|
// No instances as of now, so fill zeros for the counter data
|
|
//
|
|
pPerfCounterBlock = (PERF_COUNTER_BLOCK *)
|
|
(((PBYTE)&pReplicaConnDataDefinition[1]) +
|
|
CSIZEOFDWORD);
|
|
pPerfCounterBlock->ByteLength = SizeOfReplicaConnPerformanceData;
|
|
bte = ((PBYTE) (&pPerfCounterBlock[1]));
|
|
ZeroMemory (bte, SIZEOF_REPCONN_COUNTER_DATA);
|
|
bte += SIZEOF_REPCONN_COUNTER_DATA;
|
|
*lppData = (PVOID) bte;
|
|
*lpNumObjectTypes = REPLICACONN_NUM_PERF_OBJECT_TYPES;
|
|
*lpcbTotalBytes =
|
|
(DWORD)((PBYTE) bte - (PBYTE) pReplicaConnDataDefinition);
|
|
FRC_Cl = TRUE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DWORD APIENTRY
|
|
CloseReplicaConnPerformanceData (
|
|
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(&FRC_ThrdCounter);
|
|
//
|
|
// Check to see if the open count is zero. This should never happen but
|
|
// just in case.
|
|
//
|
|
if (FRC_dwOpenCount == 0) {
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
//
|
|
// Decrement the Open count.
|
|
//
|
|
FRC_dwOpenCount--;
|
|
//
|
|
// If the open count becomes zero, free up the memory since no more threads
|
|
// are going to collect data.
|
|
//
|
|
if (FRC_dwOpenCount == 0) {
|
|
//
|
|
// Call the routine that frees up the memory.
|
|
//
|
|
FreeReplicaConnData();
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
} else {
|
|
LeaveCriticalSection(&FRC_ThrdCounter);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
FreeReplicaConnData(
|
|
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 (FRC_datapackage != NULL) {
|
|
if (FRC_datapackage->ver != NULL) {
|
|
free(FRC_datapackage->ver);
|
|
}
|
|
if (FRC_datapackage->indices != NULL) {
|
|
if (FRC_datapackage->indices->index != NULL) {
|
|
free(FRC_datapackage->indices->index);
|
|
}
|
|
free(FRC_datapackage->indices);
|
|
}
|
|
if (FRC_datapackage->instnames != NULL) {
|
|
if (FRC_datapackage->instnames->InstanceNames != NULL) {
|
|
for (j = 0; j < FRC_datapackage->numofinst; j++) {
|
|
if (FRC_datapackage->instnames->InstanceNames[j].name != NULL) {
|
|
free(FRC_datapackage->instnames->InstanceNames[j].name);
|
|
}
|
|
}
|
|
free(FRC_datapackage->instnames->InstanceNames);
|
|
}
|
|
free(FRC_datapackage->instnames);
|
|
}
|
|
free(FRC_datapackage);
|
|
FRC_datapackage = NULL;
|
|
}
|
|
|
|
//
|
|
// Free up the collect package structure.
|
|
//
|
|
if (FRC_collectpakg != NULL) {
|
|
if (FRC_collectpakg->indices != NULL) {
|
|
if (FRC_collectpakg->indices->index != NULL) {
|
|
free(FRC_collectpakg->indices->index);
|
|
}
|
|
free(FRC_collectpakg->indices);
|
|
}
|
|
if (FRC_collectpakg->databuff != NULL) {
|
|
if (FRC_collectpakg->databuff->data != NULL) {
|
|
free(FRC_collectpakg->databuff->data);
|
|
}
|
|
free(FRC_collectpakg->databuff);
|
|
}
|
|
free(FRC_collectpakg);
|
|
FRC_collectpakg = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
FRC_BindTheRpcHandle (
|
|
OUT handle_t *OutHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine binds the RPC handle to the local server
|
|
|
|
Arguments:
|
|
|
|
OutHandle: Handle to be bound
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
|
|
{
|
|
PWCHAR LocalComputerName, BindingString;
|
|
DWORD NameLen, WStatus = ERROR_SUCCESS;
|
|
handle_t Handle;
|
|
PWCHAR PrincName = NULL;
|
|
DWORD WStatus1;
|
|
|
|
//
|
|
// Get the name of the local computer
|
|
//
|
|
NameLen = MAX_COMPUTERNAME_LENGTH + 2;
|
|
LocalComputerName = (PWCHAR) FRSPerfAlloc (NameLen * sizeof(WCHAR));
|
|
if (LocalComputerName == NULL) {
|
|
return ERROR_NO_SYSTEM_RESOURCES;
|
|
}
|
|
if (!GetComputerNameW(LocalComputerName, &NameLen)) {
|
|
WStatus = GetLastError();
|
|
free(LocalComputerName);
|
|
return WStatus;
|
|
}
|
|
|
|
//
|
|
// Create the binding string. Since we are always
|
|
// calling the local computer bind using local rpc.
|
|
// Server side of perfmon denies all calls that do not
|
|
// come over local rpc (ncalrpc).
|
|
//
|
|
WStatus = RpcStringBindingComposeW(NULL, L"ncalrpc", LocalComputerName,
|
|
NULL, NULL, &BindingString);
|
|
if (WStatus != RPC_S_OK) {
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//
|
|
// Store the binding in the handle
|
|
//
|
|
WStatus = RpcBindingFromStringBindingW(BindingString, &Handle);
|
|
if (WStatus != RPC_S_OK) {
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//
|
|
// Resolve the handle to a dynamic end point
|
|
//
|
|
WStatus = RpcEpResolveBinding(Handle, PerfFrs_ClientIfHandle);
|
|
if (WStatus != RPC_S_OK) {
|
|
WStatus1 = RpcBindingFree(&Handle);
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//
|
|
// Find the principle name
|
|
//
|
|
WStatus = RpcMgmtInqServerPrincName(Handle,
|
|
RPC_C_AUTHN_GSS_NEGOTIATE,
|
|
&PrincName);
|
|
if (WStatus != RPC_S_OK) {
|
|
WStatus1 = RpcBindingFree(&Handle);
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Set authentication info. LocalRPC only works with
|
|
// NTLM.
|
|
//
|
|
WStatus = RpcBindingSetAuthInfo(Handle,
|
|
PrincName,
|
|
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
RPC_C_AUTHN_WINNT,
|
|
NULL,
|
|
RPC_C_AUTHZ_NONE);
|
|
if (WStatus != RPC_S_OK) {
|
|
WStatus1 = RpcBindingFree(&Handle);
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//
|
|
// Success
|
|
//
|
|
*OutHandle = Handle;
|
|
|
|
CLEANUP:
|
|
|
|
free(LocalComputerName);
|
|
RpcStringFreeW(&BindingString);
|
|
|
|
if (PrincName) {
|
|
RpcStringFreeW(&PrincName);
|
|
}
|
|
|
|
return WStatus;
|
|
|
|
}
|
|
|