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;
|
|||
|
|
|||
|
}
|