926 lines
26 KiB
C
926 lines
26 KiB
C
/*++ BUILD Version: 0002 // Increment this if a change has global effects
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
perfnbt.c
|
||
|
||
Abstract:
|
||
|
||
This file implements the Extensible Objects for
|
||
the LAN object types
|
||
|
||
Created:
|
||
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
//
|
||
// include files
|
||
//
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <ntstatus.h>
|
||
#include <windows.h>
|
||
#include <fcntl.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <winperf.h>
|
||
#include "perfctr.h" // error message definition
|
||
#include "perfmsg.h"
|
||
#include "perfutil.h"
|
||
#include "perfnbt.h"
|
||
#include "datanbt.h"
|
||
|
||
// New header file for getting nbt data
|
||
#pragma warning (disable : 4201)
|
||
#include <tdi.h>
|
||
#include <nbtioctl.h>
|
||
#pragma warning (default : 4201)
|
||
|
||
enum eSTATE
|
||
{
|
||
NBT_RECONNECTING, // waiting for the worker thread to run NbtConnect
|
||
NBT_IDLE, // not Transport connection
|
||
NBT_ASSOCIATED, // associated with an address element
|
||
NBT_CONNECTING, // establishing Transport connection
|
||
NBT_SESSION_INBOUND, // waiting for a session request after tcp connection setup inbound
|
||
NBT_SESSION_WAITACCEPT, // waiting for accept after a listen has been satisfied
|
||
NBT_SESSION_OUTBOUND, // waiting for a session response after tcp connection setup
|
||
NBT_SESSION_UP, // got positive response
|
||
NBT_DISCONNECTING, // sent a disconnect down to Tcp, but it hasn't completed yet
|
||
NBT_DISCONNECTED // a session has been disconnected but not closed with TCP yet
|
||
};
|
||
|
||
//
|
||
// References to constants which initialize the Object type definitions
|
||
//
|
||
|
||
extern NBT_DATA_DEFINITION NbtDataDefinition;
|
||
|
||
#define NBT_CONNECTION_NAME_LENGTH 17
|
||
#define NETBIOS_NAME_SIZE NBT_CONNECTION_NAME_LENGTH-1
|
||
|
||
//
|
||
// Nbt data structures
|
||
//
|
||
|
||
typedef struct _NBT_DEVICE_DATA {
|
||
HANDLE hFileHandle;
|
||
UNICODE_STRING DeviceName;
|
||
} NBT_DEVICE_DATA, *PNBT_DEVICE_DATA;
|
||
|
||
PNBT_DEVICE_DATA pNbtDeviceData;
|
||
int MaxNbtDeviceName;
|
||
int NumberOfNbtDevices;
|
||
|
||
// initial count - will update to last
|
||
PVOID pNbtDataBuffer = NULL;
|
||
int NbtDataBufferSize;
|
||
|
||
DWORD dwNbtRefCount = 0;
|
||
|
||
// HANDLE NbtHandle = INVALID_HANDLE_VALUE; // Handle of Nbt Device
|
||
|
||
|
||
#define NBT_CONTROLLING_STREAM "CSB" // Ignore Controlling Stream XEB
|
||
#define NBT_LISTEN_CONNECTION 3 // All NBT connections with type <= 3,
|
||
// are just listening for clients
|
||
|
||
|
||
// The error value returned by the perfctrs.dll when an error occurs while we
|
||
// are getting the data for the NBT connections.
|
||
// The error codes we get from the socket calls (OpenStream(), s_ioctl(),
|
||
// getmsg()) are Unix errors, not Dos or Windows errors. Hopefully, somebody
|
||
// will implement the conversion from these errors to Windows errors.
|
||
// The error value is not used within the Collect data routine because this
|
||
// routine shouldn't return an error in case it fails to collect Nbt data from
|
||
// connections. In this case, it just returns the buffer it was supposed to
|
||
// place the data into, unchanged.
|
||
|
||
#define ERROR_NBT_NET_RESPONSE \
|
||
(RtlNtStatusToDosError(STATUS_INVALID_NETWORK_RESPONSE))
|
||
|
||
#define BUFF_SIZE 650
|
||
|
||
PM_OPEN_PROC OpenNbtPerformanceData;
|
||
PM_COLLECT_PROC CollectNbtPerformanceData;
|
||
PM_CLOSE_PROC CloseNbtPerformanceData;
|
||
|
||
//------------------------------------------------------------------------
|
||
NTSTATUS
|
||
OpenNbt(
|
||
IN char *path,
|
||
OUT PHANDLE pHandle,
|
||
OUT UNICODE_STRING *uc_name_string
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function opens a stream.
|
||
|
||
Arguments:
|
||
|
||
path - path to the STREAMS driver
|
||
oflag - currently ignored. In the future, O_NONBLOCK will be
|
||
relevant.
|
||
ignored - not used
|
||
|
||
Return Value:
|
||
|
||
An NT handle for the stream, or INVALID_HANDLE_VALUE if unsuccessful.
|
||
|
||
--*/
|
||
|
||
{
|
||
HANDLE StreamHandle;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
STRING name_string;
|
||
// UNICODE_STRING uc_name_string;
|
||
NTSTATUS status;
|
||
|
||
RtlInitString(&name_string, path);
|
||
RtlAnsiStringToUnicodeString(uc_name_string, &name_string, TRUE);
|
||
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
uc_name_string,
|
||
OBJ_CASE_INSENSITIVE,
|
||
(HANDLE) NULL,
|
||
(PSECURITY_DESCRIPTOR) NULL
|
||
);
|
||
|
||
status =
|
||
NtCreateFile(
|
||
&StreamHandle,
|
||
SYNCHRONIZE | FILE_READ_DATA ,
|
||
// SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
FILE_OPEN_IF,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
// RtlFreeUnicodeString(&uc_name_string);
|
||
|
||
*pHandle = StreamHandle;
|
||
|
||
return(status);
|
||
|
||
} // Open_nbt
|
||
|
||
NTSTATUS
|
||
DeviceIoCtrl(
|
||
IN HANDLE fd,
|
||
IN PVOID ReturnBuffer,
|
||
IN ULONG BufferSize,
|
||
IN ULONG Ioctl
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure performs an ioctl(I_STR) on a stream.
|
||
|
||
Arguments:
|
||
|
||
fd - NT file handle
|
||
iocp - pointer to a strioctl structure
|
||
|
||
Return Value:
|
||
|
||
0 if successful, -1 otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
TDI_REQUEST_QUERY_INFORMATION QueryInfo;
|
||
IO_STATUS_BLOCK iosb;
|
||
PVOID pInput;
|
||
ULONG SizeInput;
|
||
|
||
if (Ioctl == IOCTL_TDI_QUERY_INFORMATION)
|
||
{
|
||
pInput = &QueryInfo;
|
||
QueryInfo.QueryType = TDI_QUERY_ADAPTER_STATUS; // node status or whatever
|
||
SizeInput = sizeof(TDI_REQUEST_QUERY_INFORMATION);
|
||
}
|
||
else
|
||
{
|
||
pInput = NULL;
|
||
SizeInput = 0;
|
||
}
|
||
|
||
status = NtDeviceIoControlFile(
|
||
fd, // Handle
|
||
NULL, // Event
|
||
NULL, // ApcRoutine
|
||
NULL, // ApcContext
|
||
&iosb, // IoStatusBlock
|
||
Ioctl, // IoControlCode
|
||
pInput, // InputBuffer
|
||
SizeInput, // InputBufferSize
|
||
(PVOID) ReturnBuffer, // OutputBuffer
|
||
BufferSize); // OutputBufferSize
|
||
|
||
|
||
if (status == STATUS_PENDING)
|
||
{
|
||
status = NtWaitForSingleObject(
|
||
fd, // Handle
|
||
TRUE, // Alertable
|
||
NULL); // Timeout
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // DeviceIoCtrl
|
||
|
||
|
||
PCHAR
|
||
printable(
|
||
IN PCHAR string,
|
||
IN PCHAR StrOut
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure converts non prinatble characaters to periods ('.')
|
||
|
||
Arguments:
|
||
string - the string to convert
|
||
StrOut - ptr to a string to put the converted string into
|
||
|
||
Return Value:
|
||
|
||
a ptr to the string that was converted (Strout)
|
||
|
||
--*/
|
||
{
|
||
PCHAR Out;
|
||
PCHAR cp;
|
||
LONG i;
|
||
|
||
Out = StrOut;
|
||
for (cp = string, i= 0; i < NETBIOS_NAME_SIZE; cp++,i++) {
|
||
if (isprint(*cp)) {
|
||
*Out++ = *cp;
|
||
continue;
|
||
}
|
||
|
||
if (*cp >= 128) { /* extended characters are ok */
|
||
*Out++ = *cp;
|
||
continue;
|
||
}
|
||
*Out++ = '.';
|
||
}
|
||
return(StrOut);
|
||
} // printable
|
||
|
||
|
||
|
||
#pragma warning ( disable : 4127)
|
||
DWORD
|
||
OpenNbtPerformanceData (
|
||
IN LPWSTR dwVoid // not used by this routine
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Routine Description:
|
||
|
||
This routine will open the Nbt device and remember the handle returned
|
||
by the device.
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
|
||
Return Value:
|
||
|
||
ERROR_NBT_NET_RESPONSE if unable to open NBT stream device
|
||
|
||
ERROR_SUCCESS if open was successful
|
||
|
||
--*/
|
||
{
|
||
PCHAR SubKeyLinkage=(PCHAR)"system\\currentcontrolset\\services\\netbt\\linkage";
|
||
PCHAR Linkage=(PCHAR)"Export";
|
||
CHAR *pBuffer = NULL;
|
||
CHAR *lpLocalDeviceNames;
|
||
LONG status, status2;
|
||
DWORD Type;
|
||
ULONG size;
|
||
HKEY Key;
|
||
HANDLE hFileHandle;
|
||
UNICODE_STRING fileString;
|
||
NTSTATUS ntstatus;
|
||
PNBT_DEVICE_DATA pTemp;
|
||
|
||
UNREFERENCED_PARAMETER (dwVoid);
|
||
|
||
MonOpenEventLog();
|
||
|
||
REPORT_INFORMATION (NBT_OPEN_ENTERED, LOG_VERBOSE);
|
||
|
||
if (InterlockedIncrement(&dwNbtRefCount) == 1) {
|
||
|
||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
SubKeyLinkage,
|
||
0,
|
||
KEY_READ,
|
||
&Key);
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
// now read the linkage values
|
||
size = 0;
|
||
pBuffer = NULL;
|
||
status2 = RegQueryValueEx(Key,
|
||
Linkage,
|
||
NULL,
|
||
&Type,
|
||
(LPBYTE)pBuffer,
|
||
&size);
|
||
if ((size > 0) &&
|
||
((status2 == ERROR_MORE_DATA) ||
|
||
(status2 == ERROR_SUCCESS))) {
|
||
pBuffer = RtlAllocateHeap(
|
||
RtlProcessHeap(), 0, size);
|
||
if (pBuffer == NULL) {
|
||
RegCloseKey(Key);
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
status2 = RegQueryValueEx(Key,
|
||
Linkage,
|
||
NULL,
|
||
&Type,
|
||
(LPBYTE)pBuffer,
|
||
&size);
|
||
}
|
||
RegCloseKey(Key);
|
||
if (status2 != ERROR_SUCCESS) {
|
||
if (pBuffer != NULL) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
|
||
}
|
||
return ERROR_SUCCESS;
|
||
}
|
||
}
|
||
else {
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
if (pBuffer == NULL) {
|
||
return ERROR_SUCCESS;
|
||
}
|
||
lpLocalDeviceNames = pBuffer;
|
||
while (TRUE) {
|
||
|
||
if (*lpLocalDeviceNames == '\0') {
|
||
break;
|
||
}
|
||
|
||
ntstatus = OpenNbt (lpLocalDeviceNames,
|
||
&hFileHandle,
|
||
&fileString);
|
||
|
||
if (ntstatus == ERROR_SUCCESS) {
|
||
if (NumberOfNbtDevices == 0) {
|
||
// allocate memory to hold the device data
|
||
pNbtDeviceData = RtlAllocateHeap(RtlProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
sizeof(NBT_DEVICE_DATA));
|
||
|
||
if (pNbtDeviceData == NULL) {
|
||
RtlFreeUnicodeString(&fileString);
|
||
if (pBuffer) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
|
||
}
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
}
|
||
else {
|
||
// resize to hold multiple devices
|
||
pTemp = RtlReAllocateHeap(RtlProcessHeap(), 0,
|
||
pNbtDeviceData,
|
||
sizeof(NBT_DEVICE_DATA) * (NumberOfNbtDevices + 1));
|
||
if (pTemp == NULL) {
|
||
NtClose(hFileHandle);
|
||
RtlFreeUnicodeString(&fileString);
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pNbtDeviceData);
|
||
pNbtDeviceData = NULL;
|
||
REPORT_ERROR (TDI_PROVIDER_STATS_MEMORY, LOG_USER);
|
||
break;
|
||
}
|
||
else {
|
||
pNbtDeviceData = pTemp;
|
||
}
|
||
}
|
||
|
||
// build the Data structure for this device instance
|
||
pNbtDeviceData[NumberOfNbtDevices].hFileHandle
|
||
= hFileHandle;
|
||
pNbtDeviceData[NumberOfNbtDevices].DeviceName.MaximumLength =
|
||
fileString.MaximumLength;
|
||
pNbtDeviceData[NumberOfNbtDevices].DeviceName.Length =
|
||
fileString.Length;
|
||
pNbtDeviceData[NumberOfNbtDevices].DeviceName.Buffer =
|
||
fileString.Buffer;
|
||
NumberOfNbtDevices++;
|
||
|
||
if (fileString.MaximumLength > MaxNbtDeviceName) {
|
||
MaxNbtDeviceName = fileString.MaximumLength;
|
||
}
|
||
} // ntstatus OK
|
||
else {
|
||
RtlFreeUnicodeString(&fileString);
|
||
}
|
||
|
||
// increment to the next device string
|
||
// lpLocalDeviceNames += strlen(lpLocalDeviceNames) + 1;
|
||
// we only support one device at this point since we cannot
|
||
// tell which Connection goes with which device
|
||
break;
|
||
|
||
} // while TRUE
|
||
}
|
||
|
||
REPORT_SUCCESS (NBT_OPEN_PERFORMANCE_DATA, LOG_DEBUG);
|
||
if (pBuffer) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
|
||
}
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
#pragma warning ( default : 4127)
|
||
|
||
|
||
DWORD
|
||
CollectNbtPerformanceData(
|
||
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 Nbt counters.
|
||
|
||
IN LPWSTR lpValueName
|
||
pointer to a wide character null-terminated string passed by the
|
||
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 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 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.
|
||
--*/
|
||
{
|
||
|
||
// Variables for reformatting the Nbt data
|
||
|
||
LARGE_INTEGER UNALIGNED *pliCounter;
|
||
NBT_DATA_DEFINITION *pNbtDataDefinition;
|
||
PPERF_OBJECT_TYPE pNbtObject;
|
||
ULONG SpaceNeeded;
|
||
UNICODE_STRING ConnectionName;
|
||
ANSI_STRING AnsiConnectionName;
|
||
WCHAR ConnectionNameBuffer[NBT_CONNECTION_NAME_LENGTH + 20];
|
||
#if 0
|
||
// be sure to check the reference below...
|
||
WCHAR DeviceNameBuffer[NBT_CONNECTION_NAME_LENGTH + 1 + 128];
|
||
#endif
|
||
CHAR AnsiConnectionNameBuffer[NBT_CONNECTION_NAME_LENGTH + 1 + 20];
|
||
WCHAR TotalName[] = L"Total";
|
||
PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition;
|
||
PERF_COUNTER_BLOCK *pPerfCounterBlock;
|
||
CHAR NameOut[NETBIOS_NAME_SIZE +4];
|
||
|
||
// int ConnectionCounter = 0; /* this is not used anymore */
|
||
LARGE_INTEGER TotalReceived, TotalSent;
|
||
|
||
DWORD dwDataReturn[2];
|
||
NTSTATUS status;
|
||
tCONNECTION_LIST *pConList;
|
||
tCONNECTIONS *pConns;
|
||
LONG Count;
|
||
int i;
|
||
int NumberOfConnections = 5; // assume 5 to start
|
||
PVOID pOldBuffer;
|
||
|
||
if (lpValueName == NULL) {
|
||
REPORT_INFORMATION (NBT_COLLECT_ENTERED, LOG_VERBOSE);
|
||
} else {
|
||
REPORT_INFORMATION_DATA (NBT_COLLECT_ENTERED, LOG_VERBOSE,
|
||
lpValueName, (lstrlenW(lpValueName) * sizeof(WCHAR)));
|
||
}
|
||
|
||
|
||
//
|
||
// define pointer for Object Data structure (NBT object def.)
|
||
//
|
||
|
||
pNbtDataDefinition = (NBT_DATA_DEFINITION *) *lppData;
|
||
pNbtObject = (PPERF_OBJECT_TYPE) pNbtDataDefinition;
|
||
|
||
if (!pNbtDeviceData || NumberOfNbtDevices == 0)
|
||
{
|
||
//
|
||
// Error getting NBT info, so return 0 bytes, 0 objects and
|
||
// log error
|
||
//
|
||
if (NumberOfNbtDevices > 0) {
|
||
// only report an error if there are devices
|
||
// returning data but they can't be read.
|
||
REPORT_ERROR (NBT_IOCTL_INFO_ERROR, LOG_USER);
|
||
}
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
if (!pNbtDataBuffer)
|
||
{
|
||
NbtDataBufferSize = 1024L;
|
||
pNbtDataBuffer = RtlAllocateHeap(RtlProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
NbtDataBufferSize
|
||
);
|
||
if (!pNbtDataBuffer)
|
||
{
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
return ERROR_SUCCESS;
|
||
}
|
||
}
|
||
|
||
REPORT_SUCCESS (NBT_IOCTL_INFO_SUCCESS, LOG_VERBOSE);
|
||
|
||
|
||
// Compute space needed to hold NBT data
|
||
SpaceNeeded = sizeof(NBT_DATA_DEFINITION) +
|
||
(NumberOfConnections *
|
||
NumberOfNbtDevices *
|
||
(sizeof(PERF_INSTANCE_DEFINITION) +
|
||
QWORD_MULTIPLE((NBT_CONNECTION_NAME_LENGTH + 1) * sizeof(WCHAR)) +
|
||
QWORD_MULTIPLE(MaxNbtDeviceName)
|
||
+ SIZE_OF_NBT_DATA));
|
||
|
||
if ( *lpcbTotalBytes < SpaceNeeded ) {
|
||
dwDataReturn[0] = *lpcbTotalBytes;
|
||
dwDataReturn[1] = SpaceNeeded;
|
||
REPORT_WARNING_DATA (NBT_DATA_BUFFER_SIZE, LOG_DEBUG,
|
||
&dwDataReturn, sizeof (dwDataReturn));
|
||
return ERROR_MORE_DATA;
|
||
}
|
||
|
||
|
||
|
||
AnsiConnectionName.Length =
|
||
AnsiConnectionName.MaximumLength = sizeof(AnsiConnectionNameBuffer);
|
||
AnsiConnectionName.Buffer = AnsiConnectionNameBuffer;
|
||
//
|
||
// If here, then there's a object to display so initialize
|
||
// the Object data structure in the buffer passed to us.
|
||
//
|
||
RtlMoveMemory(pNbtDataDefinition, &NbtDataDefinition, sizeof(NBT_DATA_DEFINITION));
|
||
//
|
||
// point to where the first instance of this will be (if we find one.
|
||
//
|
||
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
|
||
(pNbtDataDefinition + 1);
|
||
|
||
TotalReceived.LowPart = 0; // initialize counters
|
||
TotalSent.LowPart = 0;
|
||
TotalReceived.HighPart = 0; // initialize counters
|
||
TotalSent.HighPart = 0;
|
||
|
||
// NOTE:- we only support NumberOfNbtDevices == 1 since
|
||
// DeviceIoCtrl can't tell which connection is for which NBT device
|
||
for (i=0; i < NumberOfNbtDevices; i++)
|
||
{
|
||
if (pNbtDeviceData[i].hFileHandle == 0 ||
|
||
pNbtDeviceData[i].hFileHandle == INVALID_HANDLE_VALUE)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
status = STATUS_BUFFER_OVERFLOW;
|
||
while (status == STATUS_BUFFER_OVERFLOW)
|
||
{
|
||
status = DeviceIoCtrl (
|
||
pNbtDeviceData[i].hFileHandle,
|
||
pNbtDataBuffer,
|
||
NbtDataBufferSize,
|
||
IOCTL_NETBT_GET_CONNECTIONS);
|
||
if (status == STATUS_BUFFER_OVERFLOW)
|
||
{
|
||
// resize to hold multiple devices
|
||
NbtDataBufferSize += 1024L;
|
||
pOldBuffer = pNbtDataBuffer;
|
||
pNbtDataBuffer = RtlReAllocateHeap(RtlProcessHeap(), 0,
|
||
pNbtDataBuffer,
|
||
NbtDataBufferSize);
|
||
|
||
if (pNbtDataBuffer == NULL || NbtDataBufferSize == 0x0FFFFL)
|
||
{
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
RtlFreeHeap(RtlProcessHeap(), 0, pOldBuffer);
|
||
pNbtDataBuffer = NULL;
|
||
return ERROR_SUCCESS;
|
||
}
|
||
}
|
||
} // while Buffer overflow
|
||
|
||
pConList = (tCONNECTION_LIST *) pNbtDataBuffer;
|
||
Count = pConList->ConnectionCount;
|
||
pConns = pConList->ConnList;
|
||
|
||
if (Count == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (NumberOfConnections < Count)
|
||
{
|
||
NumberOfConnections = Count;
|
||
|
||
// Better check space needed to hold NBT data again
|
||
// this is because the Count could be hugh
|
||
SpaceNeeded = sizeof(NBT_DATA_DEFINITION) +
|
||
(NumberOfConnections *
|
||
NumberOfNbtDevices *
|
||
(sizeof(PERF_INSTANCE_DEFINITION) +
|
||
QWORD_MULTIPLE((NBT_CONNECTION_NAME_LENGTH + 1) * sizeof(WCHAR)) +
|
||
QWORD_MULTIPLE(MaxNbtDeviceName )
|
||
+ SIZE_OF_NBT_DATA));
|
||
|
||
|
||
if ( *lpcbTotalBytes < SpaceNeeded ) {
|
||
dwDataReturn[0] = *lpcbTotalBytes;
|
||
dwDataReturn[1] = SpaceNeeded;
|
||
REPORT_WARNING_DATA (NBT_DATA_BUFFER_SIZE, LOG_DEBUG,
|
||
&dwDataReturn, sizeof (dwDataReturn));
|
||
return ERROR_MORE_DATA;
|
||
}
|
||
}
|
||
|
||
while ( Count-- )
|
||
{
|
||
if (pConns->State == NBT_SESSION_UP)
|
||
{
|
||
// only care about UP connection
|
||
|
||
if (pConns->RemoteName[0])
|
||
{
|
||
AnsiConnectionName.Length = (USHORT)sprintf (
|
||
AnsiConnectionNameBuffer,
|
||
"%16.16s",
|
||
printable(pConns->RemoteName, NameOut));
|
||
}
|
||
else if (pConns->LocalName[0])
|
||
{
|
||
if (pConns->LocalName[NETBIOS_NAME_SIZE-1] < ' ')
|
||
{
|
||
AnsiConnectionName.Length = (USHORT)sprintf (
|
||
AnsiConnectionNameBuffer,
|
||
"%15.15s%02.2X",
|
||
printable(pConns->LocalName, NameOut),
|
||
pConns->LocalName[NETBIOS_NAME_SIZE-1]);
|
||
}
|
||
else
|
||
{
|
||
AnsiConnectionName.Length = (USHORT)sprintf (
|
||
AnsiConnectionNameBuffer,
|
||
"%16.16s",
|
||
printable(pConns->LocalName, NameOut));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
AnsiConnectionNameBuffer[0] = ' ';
|
||
AnsiConnectionName.Length = 1;
|
||
}
|
||
|
||
ConnectionName.Length =
|
||
ConnectionName.MaximumLength =
|
||
sizeof(ConnectionNameBuffer);
|
||
ConnectionName.Buffer = ConnectionNameBuffer;
|
||
|
||
RtlAnsiStringToUnicodeString (&ConnectionName,
|
||
&AnsiConnectionName,
|
||
FALSE);
|
||
|
||
// no need to put in device name since we can
|
||
// only support one device
|
||
#if 0
|
||
lstrcpyW (DeviceNameBuffer, pNbtDeviceData[i].DeviceName.Buffer);
|
||
lstrcatW (DeviceNameBuffer, L" ");
|
||
lstrcatW (DeviceNameBuffer, ConnectionNameBuffer);
|
||
|
||
ConnectionName.Length =
|
||
lstrlenW (DeviceNameBuffer) * sizeof(WCHAR);
|
||
ConnectionName.MaximumLength =
|
||
sizeof(DeviceNameBuffer);
|
||
ConnectionName.Buffer = DeviceNameBuffer;
|
||
#endif
|
||
|
||
//
|
||
// load instance data into buffer
|
||
//
|
||
MonBuildInstanceDefinition (pPerfInstanceDefinition,
|
||
(PVOID *) &pPerfCounterBlock,
|
||
0,
|
||
0,
|
||
(DWORD)PERF_NO_UNIQUE_ID, // no unique ID, Use the name instead
|
||
// ConnectionCounter++,
|
||
&ConnectionName);
|
||
|
||
//
|
||
// adjust object size values to include new instance
|
||
//
|
||
|
||
pNbtObject->NumInstances++;
|
||
//
|
||
// initialize this instance's counter block
|
||
|
||
pPerfCounterBlock->ByteLength = SIZE_OF_NBT_DATA;
|
||
|
||
pliCounter = (LARGE_INTEGER UNALIGNED * ) (pPerfCounterBlock + 2);
|
||
|
||
*(pliCounter++) = pConns->BytesRcvd;
|
||
TotalReceived.QuadPart = TotalReceived.QuadPart +
|
||
pConns->BytesRcvd.QuadPart;
|
||
|
||
*pliCounter++ = pConns->BytesSent;
|
||
TotalSent.QuadPart = TotalSent.QuadPart +
|
||
pConns->BytesSent.QuadPart;
|
||
|
||
pliCounter->QuadPart = pConns->BytesRcvd.QuadPart +
|
||
pConns->BytesSent.QuadPart;
|
||
|
||
//
|
||
// update pointer for next instance
|
||
//
|
||
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
|
||
(((PBYTE) pPerfCounterBlock) + SIZE_OF_NBT_DATA);
|
||
|
||
} // pConns->State == NBT_SESSION_UP
|
||
|
||
pConns++;
|
||
|
||
} // while ( Count-- )
|
||
} // for i < NumberOfNbtDevices
|
||
|
||
|
||
|
||
// The last instance definition contains the total data from all the
|
||
// displayed connections
|
||
|
||
RtlInitUnicodeString (&ConnectionName, TotalName);
|
||
MonBuildInstanceDefinition (pPerfInstanceDefinition,
|
||
(PVOID *) &pPerfCounterBlock,
|
||
0,
|
||
0,
|
||
// ConnectionCounter++,
|
||
(DWORD)PERF_NO_UNIQUE_ID, // no unique ID, Use the name instead
|
||
&ConnectionName);
|
||
|
||
//
|
||
// adjust object size values to include new instance
|
||
//
|
||
|
||
pNbtObject->NumInstances++;
|
||
pNbtObject->TotalByteLength += sizeof (PERF_INSTANCE_DEFINITION)
|
||
+ SIZE_OF_NBT_DATA;
|
||
|
||
// initialize counter block for this instance
|
||
|
||
pPerfCounterBlock->ByteLength = SIZE_OF_NBT_DATA;
|
||
|
||
// load counters
|
||
|
||
pliCounter = (LARGE_INTEGER UNALIGNED * ) (pPerfCounterBlock + 2);
|
||
(*(pliCounter++)) = TotalReceived;
|
||
(*(pliCounter++)) = TotalSent;
|
||
pliCounter->QuadPart = TotalReceived.QuadPart + TotalSent.QuadPart;
|
||
pliCounter++;
|
||
|
||
// Set returned values
|
||
*lppData = (LPVOID)pliCounter;
|
||
|
||
*lpNumObjectTypes = NBT_NUM_PERF_OBJECT_TYPES;
|
||
*lpcbTotalBytes = (DWORD)((LPBYTE)pliCounter-(LPBYTE)pNbtObject);
|
||
|
||
pNbtDataDefinition->NbtObjectType.TotalByteLength = *lpcbTotalBytes;
|
||
|
||
REPORT_INFORMATION (NBT_COLLECT_DATA, LOG_DEBUG);
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
CloseNbtPerformanceData(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine closes the open handles to Nbt devices.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
int i;
|
||
|
||
REPORT_INFORMATION (NBT_CLOSE, LOG_VERBOSE);
|
||
|
||
if (InterlockedDecrement(&dwNbtRefCount) == 0) {
|
||
if (pNbtDeviceData) {
|
||
for (i=0; i < NumberOfNbtDevices; i++) {
|
||
if (pNbtDeviceData[i].DeviceName.Buffer) {
|
||
RtlFreeUnicodeString(&(pNbtDeviceData[i].DeviceName));
|
||
}
|
||
|
||
if (pNbtDeviceData[i].hFileHandle) {
|
||
NtClose (pNbtDeviceData[i].hFileHandle);
|
||
}
|
||
}
|
||
|
||
RtlFreeHeap( RtlProcessHeap(), 0, pNbtDeviceData);
|
||
|
||
pNbtDeviceData = NULL;
|
||
NumberOfNbtDevices = 0;
|
||
}
|
||
|
||
|
||
if (pNbtDataBuffer) {
|
||
RtlFreeHeap( RtlProcessHeap(), 0, pNbtDataBuffer);
|
||
pNbtDataBuffer = NULL;
|
||
NbtDataBufferSize = 0;
|
||
}
|
||
}
|
||
|
||
MonCloseEventLog();
|
||
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|