windows-nt/Source/XPSP1/NT/base/screg/winreg/perfdlls/perfctrs/perfnbf.c
2020-09-26 16:20:57 +08:00

1474 lines
44 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++ BUILD Version: 0001 // Increment this if a change has global effects
Copyright (c) 1992 Microsoft Corporation
Module Name:
perfnbf.c
Abstract:
This file implements the Extensible Objects for
the Nbf LAN object types
This code originally existed for NetBEUI only. Later, it was
adaped to handle Netrware protocol level NWNB, SPX, and IPX.
The code was not everywhere changed to reflect this, due to the
lateness of the change. Therefore, sometimes you will see NBF
where you should see TDI.
Created:
Russ Blake 07/30/92
Revision History
--*/
//
// Include Files
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntprfctr.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <nb30.h>
#include <tdi.h>
#include <winperf.h>
#include "perfctr.h" // error message definition
#include "perfmsg.h"
#include "perfutil.h"
#include "datanbf.h"
//
// References to constants which initialize the Object type definitions
//
extern NBF_DATA_DEFINITION NbfDataDefinition;
extern NBF_RESOURCE_DATA_DEFINITION NbfResourceDataDefinition;
//
// TDI data structures
//
#define NBF_PROTOCOL 0
#define IPX_PROTOCOL 1
#define SPX_PROTOCOL 2
#define NWNB_PROTOCOL 3
#define NUMBER_OF_PROTOCOLS_HANDLED 4
typedef struct _TDI_DATA_DEFINITION {
int NumberOfResources;
HANDLE fileHandle;
UNICODE_STRING DeviceName;
} TDI_DATA_DEFINITION, *PTDI_DATA_DEFINITION;
typedef struct _TDI_PROTOCOLS_DATA {
int NumOfDevices;
int MaxDeviceName;
int MaxNumOfResources;
PTDI_DATA_DEFINITION pTDIData;
} TDI_PROTOCOLS_DATA;
TDI_PROTOCOLS_DATA TDITbl[NUMBER_OF_PROTOCOLS_HANDLED];
DWORD dwTdiProtocolRefCount[NUMBER_OF_PROTOCOLS_HANDLED] = {0,0,0,0};
DWORD dwTdiRefCount = 0;
DWORD ObjectNameTitleIndices[NUMBER_OF_PROTOCOLS_HANDLED] = { 492,
488,
490,
398 };
//
// NBF data structures
//
ULONG ProviderStatsLength; // Resource-dependent size
PTDI_PROVIDER_STATISTICS ProviderStats = NULL;
// Provider statistics
//
// NetBUEI Resource Instance Names
//
LPCWSTR NetResourceName[] =
{
(LPCWSTR)L"Link(11)",
(LPCWSTR)L"Address(12)",
(LPCWSTR)L"Address File(13)",
(LPCWSTR)L"Connection(14)",
(LPCWSTR)L"Request(15)",
(LPCWSTR)L"UI Frame(21)",
(LPCWSTR)L"Packet(22)",
(LPCWSTR)L"Receive Packet(23)",
(LPCWSTR)L"Receive Buffer(24)"
};
#define NUMBER_OF_NAMES sizeof(NetResourceName)/sizeof(NetResourceName[0])
#define MAX_NBF_RESOURCE_NAME_LENGTH 20
//
// Function Prototypes
//
PM_OPEN_PROC OpenNbfPerformanceData;
PM_COLLECT_PROC CollectNbfPerformanceData;
PM_CLOSE_PROC CloseNbfPerformanceData;
PM_OPEN_PROC OpenIPXPerformanceData;
PM_COLLECT_PROC CollectIPXPerformanceData;
PM_CLOSE_PROC CloseIPXPerformanceData;
PM_OPEN_PROC OpenSPXPerformanceData;
PM_COLLECT_PROC CollectSPXPerformanceData;
PM_CLOSE_PROC CloseSPXPerformanceData;
PM_OPEN_PROC OpenNWNBPerformanceData;
PM_COLLECT_PROC CollectNWNBPerformanceData;
PM_CLOSE_PROC CloseNWNBPerformanceData;
DWORD OpenTDIPerformanceData(LPWSTR lpDeviceNames,
DWORD CurrentProtocol);
DWORD CollectTDIPerformanceData(IN LPWSTR lpValueName,
IN OUT LPVOID *lppData,
IN OUT LPDWORD lpcbTotalBytes,
IN OUT LPDWORD lpNumObjectTypes,
IN DWORD CurrentProtocol);
DWORD CloseTDIPerformanceData(DWORD CurrentProtocol);
DWORD
OpenNbfPerformanceData(
LPWSTR lpDeviceNames
)
/*++
Routine Description:
This routine will open each device and remember the handle
that the device returns.
Arguments:
Pointer to each device to be opened
Return Value:
None.
--*/
{
return OpenTDIPerformanceData(lpDeviceNames, NBF_PROTOCOL);
}
DWORD
OpenIPXPerformanceData(
LPWSTR lpDeviceNames
)
/*++
Routine Description:
This routine will open each device and remember the handle
that the device returns.
Arguments:
Pointer to each device to be opened
Return Value:
None.
--*/
{
return OpenTDIPerformanceData(lpDeviceNames, IPX_PROTOCOL);
}
DWORD
OpenSPXPerformanceData(
LPWSTR lpDeviceNames
)
/*++
Routine Description:
This routine will open each device and remember the handle
that the device returns.
Arguments:
Pointer to each device to be opened
Return Value:
None.
--*/
{
DWORD dwStatus;
dwStatus = OpenTDIPerformanceData(lpDeviceNames, SPX_PROTOCOL);
if (dwStatus == ERROR_FILE_NOT_FOUND) {
// no devices is not really an error, even though no counters
// will be collected, this presents a much less alarming
// message to the user.
REPORT_WARNING (SPX_NO_DEVICE, LOG_USER);
dwStatus = ERROR_SUCCESS;
}
return dwStatus;
}
DWORD
OpenNWNBPerformanceData(
LPWSTR lpDeviceNames
)
/*++
Routine Description:
This routine will open each device and remember the handle
that the device returns.
Arguments:
Pointer to each device to be opened
Return Value:
None.
--*/
{
return OpenTDIPerformanceData(lpDeviceNames, NWNB_PROTOCOL);
}
void
CleanUpTDIData (
DWORD CurrentProtocol
)
/*++
Routine Description:
This routine will celanup all the memory allocated for the
CurrentProtocol
Arguments:
IN DWORD CurrentProtocol
this is the index of the protocol for which we are currently
gathering statistics
Return Value:
None.
--*/
{
int NumOfDevices;
int i;
PTDI_DATA_DEFINITION pTDIData;
pTDIData = TDITbl[CurrentProtocol].pTDIData;
if (pTDIData == NULL)
// nothing to cleanup
return;
NumOfDevices = TDITbl[CurrentProtocol].NumOfDevices;
for (i=0; i < NumOfDevices; i++, pTDIData++) {
if (pTDIData->DeviceName.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, pTDIData->DeviceName.Buffer);
}
if (pTDIData->fileHandle) {
NtClose (pTDIData->fileHandle);
}
}
RtlFreeHeap(RtlProcessHeap(), 0,
TDITbl[CurrentProtocol].pTDIData);
TDITbl[CurrentProtocol].pTDIData = NULL;
}
#pragma warning ( disable : 4127)
DWORD
OpenTDIPerformanceData(
LPWSTR lpDeviceNames,
DWORD CurrentProtocol
)
/*++
Routine Description:
This routine will open each device and remember the handle
that the device returns.
Arguments:
IN LPWSTR lpDeviceNames
pointer to each device to be opened
IN DWORD CurrentProtocol
this is the index of the protocol for which we are currently
gathering statistics
Return Value:
None.
--*/
{
NTSTATUS Status;
UNICODE_STRING FileString;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
TDI_REQUEST_USER_QUERY_INFO QueryInfo;
HANDLE fileHandle;
LPWSTR lpLocalDeviceNames;
int NumOfDevices;
LPWSTR lpSaveDeviceName;
PTDI_DATA_DEFINITION pTemp;
PTDI_PROVIDER_INFO ProviderInfo=NULL;
BOOL bInitThisProtocol = FALSE;
MonOpenEventLog(); // this function maintains a reference count
lpLocalDeviceNames = lpDeviceNames;
if (dwTdiProtocolRefCount[CurrentProtocol] == 0) {
bInitThisProtocol = TRUE;
TDITbl[CurrentProtocol].MaxDeviceName = 0;
NumOfDevices = TDITbl[CurrentProtocol].NumOfDevices = 0;
TDITbl[CurrentProtocol].pTDIData = NULL;
while (TRUE) {
if (lpLocalDeviceNames == NULL || *lpLocalDeviceNames == L'\0') {
break;
}
REPORT_INFORMATION_DATA (TDI_OPEN_ENTERED,
LOG_VERBOSE,
lpLocalDeviceNames,
(lstrlenW(lpLocalDeviceNames) * sizeof(WCHAR)));
RtlInitUnicodeString (&FileString, lpLocalDeviceNames);
lpSaveDeviceName = RtlAllocateHeap(RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof (WCHAR) * (lstrlenW(lpLocalDeviceNames) + 1));
if (!lpSaveDeviceName) {
REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER);
if (NumOfDevices == 0)
return ERROR_OUTOFMEMORY;
else
break;
}
InitializeObjectAttributes(
&ObjectAttributes,
&FileString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(
&fileHandle,
SYNCHRONIZE | FILE_READ_DATA,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status)) {
RtlFreeHeap(RtlProcessHeap(), 0, lpSaveDeviceName);
REPORT_ERROR_DATA (TDI_OPEN_FILE_ERROR, LOG_DEBUG,
lpLocalDeviceNames, (lstrlenW(lpLocalDeviceNames) * sizeof(WCHAR)));
REPORT_ERROR_DATA (TDI_OPEN_FILE_ERROR, LOG_DEBUG,
&IoStatusBlock, sizeof(IoStatusBlock));
if (NumOfDevices == 0) {
return RtlNtStatusToDosError(Status);
} else {
break;
}
}
if (NumOfDevices == 0) {
// allocate memory to hold the device data
TDITbl[CurrentProtocol].pTDIData =
RtlAllocateHeap(RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(TDI_DATA_DEFINITION));
if (TDITbl[CurrentProtocol].pTDIData == NULL) {
REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_DEBUG);
NtClose(fileHandle);
RtlFreeHeap(RtlProcessHeap(), 0, lpSaveDeviceName);
return ERROR_OUTOFMEMORY;
}
} else {
// resize to hold multiple devices
pTemp = RtlReAllocateHeap(RtlProcessHeap(), 0,
TDITbl[CurrentProtocol].pTDIData,
sizeof(TDI_DATA_DEFINITION) * (NumOfDevices + 1));
if (pTemp == NULL) {
NtClose(fileHandle);
RtlFreeHeap(RtlProcessHeap(), 0, lpSaveDeviceName);
CleanUpTDIData(CurrentProtocol);
REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER);
return ERROR_OUTOFMEMORY;
} else {
TDITbl[CurrentProtocol].pTDIData = pTemp;
}
}
// build the TDI Data structure for this device instance
TDITbl[CurrentProtocol].pTDIData[NumOfDevices].fileHandle
= fileHandle;
TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.MaximumLength =
(WORD)(sizeof (WCHAR) * (lstrlenW(lpLocalDeviceNames) + 1));
TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.Length =
(WORD)(TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.Length - sizeof(WCHAR));
TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.Buffer =
lpSaveDeviceName;
RtlCopyUnicodeString (
&(TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName),
&FileString);
if (TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.MaximumLength
> TDITbl[CurrentProtocol].MaxDeviceName) {
TDITbl[CurrentProtocol].MaxDeviceName =
TDITbl[CurrentProtocol].pTDIData[NumOfDevices].DeviceName.MaximumLength;
}
// now increment NumOfDevices
NumOfDevices++;
TDITbl[CurrentProtocol].NumOfDevices = NumOfDevices;
// increment to the next device string
lpLocalDeviceNames += lstrlenW(lpLocalDeviceNames) + 1;
}
REPORT_INFORMATION (TDI_OPEN_FILE_SUCCESS, LOG_VERBOSE);
}
dwTdiProtocolRefCount[CurrentProtocol]++;
if (TDITbl[CurrentProtocol].NumOfDevices == 0) {
return ERROR_SUCCESS;
}
//
// The following common buffer is used by all protocols. NBF
// is bigger because of resource data returned.
//
if (ProviderStats == NULL && CurrentProtocol != NBF_PROTOCOL) {
ProviderStatsLength = sizeof(TDI_PROVIDER_STATISTICS);
ProviderStats = RtlAllocateHeap(RtlProcessHeap(),
HEAP_ZERO_MEMORY,
ProviderStatsLength);
if (ProviderStats == NULL) {
REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER);
CleanUpTDIData(CurrentProtocol);
return ERROR_OUTOFMEMORY;
}
}
if ((CurrentProtocol == NBF_PROTOCOL) && bInitThisProtocol) {
//
// Query provider info to get resource count.
//
ProviderInfo = RtlAllocateHeap(RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(TDI_PROVIDER_INFO));
if ( ProviderInfo == NULL ) {
REPORT_ERROR (TDI_PROVIDER_INFO_MEMORY, LOG_USER);
CleanUpTDIData(CurrentProtocol);
return ERROR_OUTOFMEMORY;
}
QueryInfo.QueryType = TDI_QUERY_PROVIDER_INFO;
pTemp = TDITbl[CurrentProtocol].pTDIData;
TDITbl[CurrentProtocol].MaxNumOfResources = 0;
for (NumOfDevices = 0;
NumOfDevices < TDITbl[CurrentProtocol].NumOfDevices;
NumOfDevices++, pTemp++) {
// loop thru all the devices to see if they can be opened
// if one of them fails, then stop the whole thing.
// we should probably save the good ones but...
Status = NtDeviceIoControlFile(
pTemp->fileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_TDI_QUERY_INFORMATION,
(PVOID)&QueryInfo,
sizeof(TDI_REQUEST_USER_QUERY_INFO),
(PVOID)ProviderInfo,
sizeof(TDI_PROVIDER_INFO));
pTemp->NumberOfResources = ProviderInfo->NumberOfResources;
if ((int)ProviderInfo->NumberOfResources >
TDITbl[CurrentProtocol].MaxNumOfResources) {
TDITbl[CurrentProtocol].MaxNumOfResources =
ProviderInfo->NumberOfResources;
}
if (!NT_SUCCESS(Status)) {
RtlFreeHeap(RtlProcessHeap(), 0, ProviderInfo);
REPORT_ERROR (TDI_UNABLE_READ_DEVICE, LOG_DEBUG);
REPORT_ERROR_DATA (TDI_IOCTL_FILE_ERROR, LOG_DEBUG,
&IoStatusBlock, sizeof(IoStatusBlock));
CleanUpTDIData(CurrentProtocol);
return RtlNtStatusToDosError(Status);
}
}
REPORT_INFORMATION (TDI_IOCTL_FILE, LOG_VERBOSE);
ProviderStatsLength = sizeof(TDI_PROVIDER_STATISTICS) +
(TDITbl[CurrentProtocol].MaxNumOfResources *
sizeof(TDI_PROVIDER_RESOURCE_STATS));
//
// Buffer may have been allocated smaller by other protocol.
//
if (ProviderStats != NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, ProviderStats);
}
ProviderStats = RtlAllocateHeap(RtlProcessHeap(),
HEAP_ZERO_MEMORY,
ProviderStatsLength);
if (ProviderStats == NULL) {
REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER);
RtlFreeHeap(RtlProcessHeap(), 0, ProviderInfo);
CleanUpTDIData(CurrentProtocol);
return ERROR_OUTOFMEMORY;
}
if (ProviderInfo) {
RtlFreeHeap(RtlProcessHeap(), 0, ProviderInfo);
}
}
dwTdiRefCount++;
REPORT_INFORMATION (TDI_OPEN_PERFORMANCE_DATA, LOG_DEBUG);
return ERROR_SUCCESS;
}
#pragma warning ( default : 4127)
DWORD
CollectNbfPerformanceData(
IN LPWSTR lpValueName,
IN OUT LPVOID *lppData,
IN OUT LPDWORD lpcbTotalBytes,
IN OUT LPDWORD lpNumObjectTypes
)
/*++
Routine Description:
This routine will return the data for the Nbf counters.
Arguments:
IN LPWSTR lpValueName
pointer to a wide character string passed by registry.
IN OUT LPVOID *lppData
IN: pointer to the address of the buffer to receive the completed
PerfDataBlock and subordinate structures. This routine will
append its data to the buffer starting at the point referenced
by *lppData.
OUT: points to the first byte after the data structure added by this
routine. This routine updated the value at lppdata after appending
its data.
IN OUT LPDWORD lpcbTotalBytes
IN: the address of the DWORD that tells the size in bytes of the
buffer referenced by the lppData argument
OUT: the number of bytes added by this routine is writted to the
DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes
IN: the address of the DWORD to receive the number of objects added
by this routine
OUT: the number of objects added by this routine is writted to the
DWORD pointed to by this argument
Return Value:
ERROR_MORE_DATA if buffer passed is too small to hold data
any error conditions encountered are reported to the event log if
event logging is enabled.
ERROR_SUCCESS if success or any other error. Errors, however are
also reported to the event log.
--*/
{
return CollectTDIPerformanceData(lpValueName,
lppData,
lpcbTotalBytes,
lpNumObjectTypes,
NBF_PROTOCOL);
}
DWORD
CollectIPXPerformanceData(
IN LPWSTR lpValueName,
IN OUT LPVOID *lppData,
IN OUT LPDWORD lpcbTotalBytes,
IN OUT LPDWORD lpNumObjectTypes
)
/*++
Routine Description:
This routine will return the data for the IPX counters.
Arguments:
IN LPWSTR lpValueName
pointer to a wide character string passed by registry.
IN OUT LPVOID *lppData
IN: pointer to the address of the buffer to receive the completed
PerfDataBlock and subordinate structures. This routine will
append its data to the buffer starting at the point referenced
by *lppData.
OUT: points to the first byte after the data structure added by this
routine. This routine updated the value at lppdata after appending
its data.
IN OUT LPDWORD lpcbTotalBytes
IN: the address of the DWORD that tells the size in bytes of the
buffer referenced by the lppData argument
OUT: the number of bytes added by this routine is writted to the
DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes
IN: the address of the DWORD to receive the number of objects added
by this routine
OUT: the number of objects added by this routine is writted to the
DWORD pointed to by this argument
Return Value:
ERROR_MORE_DATA if buffer passed is too small to hold data
any error conditions encountered are reported to the event log if
event logging is enabled.
ERROR_SUCCESS if success or any other error. Errors, however are
also reported to the event log.
--*/
{
return CollectTDIPerformanceData(lpValueName,
lppData,
lpcbTotalBytes,
lpNumObjectTypes,
IPX_PROTOCOL);
}
DWORD
CollectSPXPerformanceData(
IN LPWSTR lpValueName,
IN OUT LPVOID *lppData,
IN OUT LPDWORD lpcbTotalBytes,
IN OUT LPDWORD lpNumObjectTypes
)
/*++
Routine Description:
This routine will return the data for the SPX counters.
Arguments:
IN LPWSTR lpValueName
pointer to a wide character string passed by registry.
IN OUT LPVOID *lppData
IN: pointer to the address of the buffer to receive the completed
PerfDataBlock and subordinate structures. This routine will
append its data to the buffer starting at the point referenced
by *lppData.
OUT: points to the first byte after the data structure added by this
routine. This routine updated the value at lppdata after appending
its data.
IN OUT LPDWORD lpcbTotalBytes
IN: the address of the DWORD that tells the size in bytes of the
buffer referenced by the lppData argument
OUT: the number of bytes added by this routine is writted to the
DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes
IN: the address of the DWORD to receive the number of objects added
by this routine
OUT: the number of objects added by this routine is writted to the
DWORD pointed to by this argument
Return Value:
ERROR_MORE_DATA if buffer passed is too small to hold data
any error conditions encountered are reported to the event log if
event logging is enabled.
ERROR_SUCCESS if success or any other error. Errors, however are
also reported to the event log.
--*/
{
return CollectTDIPerformanceData(lpValueName,
lppData,
lpcbTotalBytes,
lpNumObjectTypes,
SPX_PROTOCOL);
}
DWORD
CollectNWNBPerformanceData(
IN LPWSTR lpValueName,
IN OUT LPVOID *lppData,
IN OUT LPDWORD lpcbTotalBytes,
IN OUT LPDWORD lpNumObjectTypes
)
/*++
Routine Description:
This routine will return the data for the NWNB counters.
Arguments:
IN LPWSTR lpValueName
pointer to a wide character string passed by registry.
IN OUT LPVOID *lppData
IN: pointer to the address of the buffer to receive the completed
PerfDataBlock and subordinate structures. This routine will
append its data to the buffer starting at the point referenced
by *lppData.
OUT: points to the first byte after the data structure added by this
routine. This routine updated the value at lppdata after appending
its data.
IN OUT LPDWORD lpcbTotalBytes
IN: the address of the DWORD that tells the size in bytes of the
buffer referenced by the lppData argument
OUT: the number of bytes added by this routine is writted to the
DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes
IN: the address of the DWORD to receive the number of objects added
by this routine
OUT: the number of objects added by this routine is writted to the
DWORD pointed to by this argument
Return Value:
ERROR_MORE_DATA if buffer passed is too small to hold data
any error conditions encountered are reported to the event log if
event logging is enabled.
ERROR_SUCCESS if success or any other error. Errors, however are
also reported to the event log.
--*/
{
return CollectTDIPerformanceData(lpValueName,
lppData,
lpcbTotalBytes,
lpNumObjectTypes,
NWNB_PROTOCOL);
}
DWORD
CollectTDIPerformanceData(
IN LPWSTR lpValueName,
IN OUT LPVOID *lppData,
IN OUT LPDWORD lpcbTotalBytes,
IN OUT LPDWORD lpNumObjectTypes,
IN DWORD CurrentProtocol
)
/*++
Routine Description:
This routine will return the data for the TDI counters.
Arguments:
IN LPWSTR lpValueName
pointer to a wide character string passed by registry.
IN OUT LPVOID *lppData
IN: pointer to the address of the buffer to receive the completed
PerfDataBlock and subordinate structures. This routine will
append its data to the buffer starting at the point referenced
by *lppData.
OUT: points to the first byte after the data structure added by this
routine. This routine updated the value at lppdata after appending
its data.
IN OUT LPDWORD lpcbTotalBytes
IN: the address of the DWORD that tells the size in bytes of the
buffer referenced by the lppData argument
OUT: the number of bytes added by this routine is writted to the
DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes
IN: the address of the DWORD to receive the number of objects added
by this routine
OUT: the number of objects added by this routine is writted to the
DWORD pointed to by this argument
IN DWORD CurrentProtocol
this is the index of the protocol for which we are currently
gathering statistics
Return Value:
ERROR_MORE_DATA if buffer passed is too small to hold data
any error conditions encountered are reported to the event log if
event logging is enabled.
ERROR_SUCCESS if success or any other error. Errors, however are
also reported to the event log.
--*/
{
// Variables for reformating the data
ULONG SpaceNeeded;
PDWORD pdwCounter = NULL;
LARGE_INTEGER UNALIGNED *pliCounter;
LARGE_INTEGER UNALIGNED *pliFrameBytes;
LARGE_INTEGER UNALIGNED *pliDatagramBytes;
PERF_COUNTER_BLOCK *pPerfCounterBlock;
NBF_DATA_DEFINITION *pNbfDataDefinition;
NBF_RESOURCE_DATA_DEFINITION *pNbfResourceDataDefinition;
// Variables for collecting the data from Nbf
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition;
TDI_REQUEST_USER_QUERY_INFO QueryInfo;
// Variables for collecting data about Nbf Resouces
int NumResource;
ULONG ResourceSpace;
UNICODE_STRING ResourceName;
WCHAR ResourceNameBuffer[MAX_NBF_RESOURCE_NAME_LENGTH + 1];
INT NumOfDevices;
PTDI_DATA_DEFINITION pTDIData;
INT i;
INT TotalNumberOfResources;
// variables used for error logging
DWORD dwDataReturn[2];
DWORD dwQueryType;
if (lpValueName == NULL) {
REPORT_INFORMATION (TDI_COLLECT_ENTERED, LOG_VERBOSE);
} else {
REPORT_INFORMATION_DATA (TDI_COLLECT_ENTERED,
LOG_VERBOSE,
lpValueName,
(DWORD)(lstrlenW(lpValueName)*sizeof(WCHAR)));
}
//
// before doing anything else,
// see if this is a foreign (i.e. non-NT) computer data request
//
dwQueryType = GetQueryType (lpValueName);
if ((dwQueryType == QUERY_COSTLY) || (dwQueryType == QUERY_FOREIGN)) {
// NBF foriegn data requests are not supported so bail out
REPORT_INFORMATION (TDI_FOREIGN_DATA_REQUEST, LOG_VERBOSE);
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS;
}
if (dwQueryType == QUERY_ITEMS){
if (CurrentProtocol == NBF_PROTOCOL) {
if ( !(IsNumberInUnicodeList (ObjectNameTitleIndices[CurrentProtocol],
lpValueName)) &&
!(IsNumberInUnicodeList (NBF_RESOURCE_OBJECT_TITLE_INDEX,
lpValueName))) {
// request received for objects not provided by NBF
REPORT_INFORMATION (TDI_UNSUPPORTED_ITEM_REQUEST, LOG_VERBOSE);
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS;
}
} // NBF_PROTOCOL
else if ( !(IsNumberInUnicodeList (ObjectNameTitleIndices[CurrentProtocol],
lpValueName))) {
// request received for objects not provided by this protocol
REPORT_INFORMATION (TDI_UNSUPPORTED_ITEM_REQUEST, LOG_VERBOSE);
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS;
} // other protocol
} // dwQueryType == QUERY_ITEMS
// if no NBF devices were opened, in the OPEN routine, then
// leave now.
if (TDITbl[CurrentProtocol].pTDIData == NULL) {
REPORT_WARNING (TDI_NULL_HANDLE, LOG_DEBUG);
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS;
}
pNbfDataDefinition = (NBF_DATA_DEFINITION *) *lppData;
pTDIData = TDITbl[CurrentProtocol].pTDIData;
NumOfDevices = TDITbl[CurrentProtocol].NumOfDevices;
// Compute space needed to hold Nbf Resource Data
if (CurrentProtocol != NBF_PROTOCOL) {
ResourceSpace = 0;
} else {
ResourceSpace = sizeof(NBF_RESOURCE_DATA_DEFINITION) +
(TDITbl[CurrentProtocol].MaxNumOfResources *
(sizeof(PERF_INSTANCE_DEFINITION) +
QWORD_MULTIPLE(
(MAX_NBF_RESOURCE_NAME_LENGTH * sizeof(WCHAR)) +
sizeof(UNICODE_NULL)) +
SIZE_OF_NBF_RESOURCE_DATA));
ResourceSpace *= NumOfDevices;
}
SpaceNeeded = sizeof(NBF_DATA_DEFINITION) +
SIZE_OF_NBF_DATA +
ResourceSpace;
// now add in the per instance NBF data
SpaceNeeded += NumOfDevices *
(SIZE_OF_NBF_DATA +
sizeof(PERF_INSTANCE_DEFINITION) +
QWORD_MULTIPLE(
(TDITbl[CurrentProtocol].MaxDeviceName * sizeof(WCHAR))
+ sizeof(UNICODE_NULL)));
if ( *lpcbTotalBytes < SpaceNeeded ) {
dwDataReturn[0] = *lpcbTotalBytes;
dwDataReturn[1] = SpaceNeeded;
REPORT_WARNING_DATA (TDI_DATA_BUFFER_SIZE_ERROR,
LOG_DEBUG,
&dwDataReturn,
sizeof(dwDataReturn));
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_MORE_DATA;
}
REPORT_INFORMATION (TDI_DATA_BUFFER_SIZE_SUCCESS, LOG_VERBOSE);
//
// Copy the (constant, initialized) Object Type and counter definitions
//
RtlMoveMemory(pNbfDataDefinition,
&NbfDataDefinition,
sizeof(NBF_DATA_DEFINITION));
pNbfDataDefinition->NbfObjectType.ObjectNameTitleIndex =
ObjectNameTitleIndices[CurrentProtocol];
pNbfDataDefinition->NbfObjectType.ObjectHelpTitleIndex =
ObjectNameTitleIndices[CurrentProtocol] + 1;
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
&pNbfDataDefinition[1];
if (NumOfDevices > 0) {
for (i=0; i < NumOfDevices; i++, pTDIData++) {
//
// Format and collect Nbf data
//
QueryInfo.QueryType = TDI_QUERY_PROVIDER_STATISTICS;
Status = NtDeviceIoControlFile(
pTDIData->fileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_TDI_QUERY_INFORMATION,
(PVOID)&QueryInfo,
sizeof(TDI_REQUEST_USER_QUERY_INFO),
(PVOID)ProviderStats,
ProviderStatsLength);
if (Status != STATUS_SUCCESS) {
REPORT_ERROR (TDI_UNABLE_READ_DEVICE, LOG_DEBUG);
REPORT_ERROR_DATA (TDI_QUERY_INFO_ERROR,
LOG_DEBUG,
&IoStatusBlock,
sizeof (IoStatusBlock));
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS;
}
REPORT_INFORMATION (TDI_QUERY_INFO_SUCCESS, LOG_DEBUG);
MonBuildInstanceDefinition(
pPerfInstanceDefinition,
(PVOID *)&pPerfCounterBlock,
0,
0,
(DWORD)PERF_NO_UNIQUE_ID,
&(pTDIData->DeviceName));
pPerfCounterBlock->ByteLength = SIZE_OF_NBF_DATA;
pdwCounter = (PDWORD) (&pPerfCounterBlock[1]);
*pdwCounter = ProviderStats->DatagramsSent +
ProviderStats->DatagramsReceived;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
pliDatagramBytes = pliCounter;
pliCounter->QuadPart = ProviderStats->DatagramBytesSent.QuadPart +
ProviderStats->DatagramBytesReceived.QuadPart;
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->PacketsSent + ProviderStats->PacketsReceived;
*++pdwCounter = ProviderStats->DataFramesSent +
ProviderStats->DataFramesReceived;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
pliFrameBytes = pliCounter;
pliCounter->QuadPart = ProviderStats->DataFrameBytesSent.QuadPart +
ProviderStats->DataFrameBytesReceived.QuadPart;
// Get the Bytes Total/sec which is the sum of Frame Byte /sec
// and Datagram byte/sec
++pliCounter;
pliCounter->QuadPart = pliDatagramBytes->QuadPart +
pliFrameBytes->QuadPart;
//
// Get the TDI raw data.
//
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->OpenConnections;
*++pdwCounter = ProviderStats->ConnectionsAfterNoRetry;
*++pdwCounter = ProviderStats->ConnectionsAfterRetry;
*++pdwCounter = ProviderStats->LocalDisconnects;
*++pdwCounter = ProviderStats->RemoteDisconnects;
*++pdwCounter = ProviderStats->LinkFailures;
*++pdwCounter = ProviderStats->AdapterFailures;
*++pdwCounter = ProviderStats->SessionTimeouts;
*++pdwCounter = ProviderStats->CancelledConnections;
*++pdwCounter = ProviderStats->RemoteResourceFailures;
*++pdwCounter = ProviderStats->LocalResourceFailures;
*++pdwCounter = ProviderStats->NotFoundFailures;
*++pdwCounter = ProviderStats->NoListenFailures;
*++pdwCounter = ProviderStats->DatagramsSent;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
*pliCounter = ProviderStats->DatagramBytesSent;
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->DatagramsReceived;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
*pliCounter = ProviderStats->DatagramBytesReceived;
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->PacketsSent;
*++pdwCounter = ProviderStats->PacketsReceived;
*++pdwCounter = ProviderStats->DataFramesSent;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
*pliCounter = ProviderStats->DataFrameBytesSent;
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->DataFramesReceived;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
*pliCounter = ProviderStats->DataFrameBytesReceived;
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->DataFramesResent;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
*pliCounter = ProviderStats->DataFrameBytesResent;
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->DataFramesRejected;
pliCounter = (LARGE_INTEGER UNALIGNED *) ++pdwCounter;
*pliCounter = ProviderStats->DataFrameBytesRejected;
pdwCounter = (PDWORD) ++pliCounter;
*pdwCounter = ProviderStats->ResponseTimerExpirations;
*++pdwCounter = ProviderStats->AckTimerExpirations;
*++pdwCounter = ProviderStats->MaximumSendWindow;
*++pdwCounter = ProviderStats->AverageSendWindow;
*++pdwCounter = ProviderStats->PiggybackAckQueued;
*++pdwCounter = ProviderStats->PiggybackAckTimeouts;
*++pdwCounter = 0; //reserved
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
((PBYTE) pPerfCounterBlock +
SIZE_OF_NBF_DATA);
}
pNbfResourceDataDefinition = (NBF_RESOURCE_DATA_DEFINITION *)
++pdwCounter;
} else {
pNbfResourceDataDefinition = (NBF_RESOURCE_DATA_DEFINITION *)
pPerfInstanceDefinition;
}
TotalNumberOfResources = 0;
pNbfDataDefinition->NbfObjectType.NumInstances = NumOfDevices;
pNbfDataDefinition->NbfObjectType.TotalByteLength =
(DWORD)((PBYTE) pdwCounter - (PBYTE) pNbfDataDefinition);
if (CurrentProtocol == NBF_PROTOCOL) {
RtlMoveMemory(pNbfResourceDataDefinition,
&NbfResourceDataDefinition,
sizeof(NBF_RESOURCE_DATA_DEFINITION));
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
&pNbfResourceDataDefinition[1];
pTDIData = TDITbl[CurrentProtocol].pTDIData;
for (i = 0; i < NumOfDevices; i++, pTDIData++) {
// for most cases, we will have only one deivce,
// then we could just use the ProviderStats read
// for NBF data.
if (NumOfDevices > 1) {
// need to read ProviderStat again for multiple devices
QueryInfo.QueryType = TDI_QUERY_PROVIDER_STATISTICS;
Status = NtDeviceIoControlFile(
pTDIData->fileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_TDI_QUERY_INFORMATION,
(PVOID)&QueryInfo,
sizeof(TDI_REQUEST_USER_QUERY_INFO),
(PVOID)ProviderStats,
ProviderStatsLength);
if (Status != STATUS_SUCCESS) {
REPORT_ERROR (TDI_UNABLE_READ_DEVICE, LOG_DEBUG);
REPORT_ERROR_DATA (TDI_QUERY_INFO_ERROR,
LOG_DEBUG,
&IoStatusBlock,
sizeof (IoStatusBlock));
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS;
}
}
TotalNumberOfResources += pTDIData->NumberOfResources;
for ( NumResource = 0;
NumResource < pTDIData->NumberOfResources;
NumResource++ ) {
//
// Format and collect Nbf Resource data
//
if (NumResource < NUMBER_OF_NAMES) {
RtlInitUnicodeString(&ResourceName,
NetResourceName[NumResource]);
} else {
ResourceName.Length = 0;
ResourceName.MaximumLength = MAX_NBF_RESOURCE_NAME_LENGTH +
sizeof(UNICODE_NULL);
ResourceName.Buffer = ResourceNameBuffer;
RtlIntegerToUnicodeString(NumResource,
10,
&ResourceName);
}
MonBuildInstanceDefinition(
pPerfInstanceDefinition,
(PVOID *)&pPerfCounterBlock,
ObjectNameTitleIndices[CurrentProtocol],
i,
(DWORD)PERF_NO_UNIQUE_ID,
&ResourceName);
pPerfCounterBlock->ByteLength = SIZE_OF_NBF_RESOURCE_DATA;
pdwCounter = (PDWORD)&pPerfCounterBlock[1]; // define pointer to first
// counter in block
*pdwCounter++ =
ProviderStats->ResourceStats[NumResource].MaximumResourceUsed;
*pdwCounter++ =
ProviderStats->ResourceStats[NumResource].AverageResourceUsed;
*pdwCounter++ =
ProviderStats->ResourceStats[NumResource].ResourceExhausted;
// set pointer to where next instance buffer should show up
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
((PBYTE) pPerfCounterBlock +
SIZE_OF_NBF_RESOURCE_DATA);
// set for loop termination
pdwCounter = (PDWORD) pPerfInstanceDefinition;
} // NumberOfResources
} // NumOfDevices
} // NBF_PROTOCOL
*lppData = pdwCounter;
pNbfResourceDataDefinition->NbfResourceObjectType.TotalByteLength =
(DWORD)((PBYTE) pdwCounter - (PBYTE) pNbfResourceDataDefinition);
if (CurrentProtocol != NBF_PROTOCOL) {
*lpNumObjectTypes = 1;
// bytes used are those of the first (i.e. only) object returned
*lpcbTotalBytes = pNbfDataDefinition->NbfObjectType.TotalByteLength;
} else {
// set count of object types returned
*lpNumObjectTypes = NBF_NUM_PERF_OBJECT_TYPES;
// set length of this object
*lpcbTotalBytes;
// note the bytes used by first object
*lpcbTotalBytes = pNbfDataDefinition->NbfObjectType.TotalByteLength;
// add the bytes used by the second object
*lpcbTotalBytes +=
pNbfResourceDataDefinition->NbfResourceObjectType.TotalByteLength;
// set number of instances loaded
pNbfResourceDataDefinition->NbfResourceObjectType.NumInstances =
TotalNumberOfResources;
}
REPORT_INFORMATION (TDI_COLLECT_DATA, LOG_DEBUG);
return ERROR_SUCCESS;
}
DWORD
CloseNbfPerformanceData(
)
/*++
Routine Description:
This routine closes the open handles to Nbf devices.
Arguments:
None.
Return Value:
ERROR_SUCCESS
--*/
{
return CloseTDIPerformanceData(NBF_PROTOCOL);
}
DWORD
CloseIPXPerformanceData(
)
/*++
Routine Description:
This routine closes the open handles to IPX devices.
Arguments:
None.
Return Value:
ERROR_SUCCESS
--*/
{
return CloseTDIPerformanceData(IPX_PROTOCOL);
}
DWORD
CloseSPXPerformanceData(
)
/*++
Routine Description:
This routine closes the open handles to SPX devices.
Arguments:
None.
Return Value:
ERROR_SUCCESS
--*/
{
return CloseTDIPerformanceData(SPX_PROTOCOL);
}
DWORD
CloseNWNBPerformanceData(
)
/*++
Routine Description:
This routine closes the open handles to NWNB devices.
Arguments:
None.
Return Value:
ERROR_SUCCESS
--*/
{
return CloseTDIPerformanceData(NWNB_PROTOCOL);
}
DWORD
CloseTDIPerformanceData(
DWORD CurrentProtocol
)
/*++
Routine Description:
This routine closes the open handles to TDI devices.
Arguments:
Current protocol index.
Return Value:
ERROR_SUCCESS
--*/
{
REPORT_INFORMATION (TDI_CLOSE_ENTERED, LOG_VERBOSE);
if (dwTdiProtocolRefCount[CurrentProtocol] > 0) {
dwTdiProtocolRefCount[CurrentProtocol]--;
if (dwTdiProtocolRefCount[CurrentProtocol] == 0) {
CleanUpTDIData (CurrentProtocol);
}
}
if (dwTdiRefCount > 0) {
dwTdiRefCount--;
if (dwTdiRefCount == 0) {
if ( ProviderStats ) {
RtlFreeHeap(RtlProcessHeap(), 0, ProviderStats);
ProviderStats = NULL;
REPORT_INFORMATION (TDI_PROVIDER_STATS_FREED, LOG_VERBOSE);
}
}
}
MonCloseEventLog ();
return ERROR_SUCCESS;
}