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.
933 lines
33 KiB
933 lines
33 KiB
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1993 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
perfftp.cxx
|
|
|
|
This file implements the Extensible Performance Objects for
|
|
the FTP Server service.
|
|
|
|
|
|
FILE HISTORY:
|
|
KeithMo 07-Jun-1993 Created, based on RussBl's sample code.
|
|
|
|
MuraliK 16-Nov-1995 Modified dependencies and removed NetApi
|
|
SophiaC 06-Nov-1996 Supported mutlitiple instances
|
|
*/
|
|
|
|
#define INITGUID
|
|
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
#include <lm.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ole2.h>
|
|
|
|
#include "iis64.h"
|
|
#include "dbgutil.h"
|
|
#include "iisinfo.h"
|
|
#include "ftpd.h"
|
|
#include "ftpctrs.h"
|
|
#include "ftpmsg.h"
|
|
#include "iadm.h"
|
|
|
|
extern "C" {
|
|
#include "perfutil.h"
|
|
#include "apiutil.h"
|
|
#include "ftpdata.h"
|
|
} // extern "C"
|
|
|
|
#define APP_NAME (TEXT("FTPCtrs"))
|
|
#define MAX_SIZEOF_INSTANCE_NAME METADATA_MAX_NAME_LEN
|
|
#define TOTAL_INSTANCE_NAME L"_Total"
|
|
|
|
//
|
|
// Private globals.
|
|
//
|
|
|
|
DWORD cOpens = 0; // Active "opens" reference count.
|
|
BOOL fInitOK = FALSE; // TRUE if DLL initialized OK.
|
|
|
|
HANDLE hEventLog = NULL; // event log handle
|
|
|
|
//
|
|
// Public prototypes.
|
|
//
|
|
|
|
PM_OPEN_PROC OpenFtpPerformanceData;
|
|
PM_COLLECT_PROC CollectFtpPerformanceData;
|
|
PM_CLOSE_PROC CloseFtpPerformanceData;
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
VOID
|
|
CopyStatisticsData(
|
|
IN FTP_STATISTICS_0 * pFTPStats,
|
|
OUT FTPD_COUNTER_BLOCK * pCounterBlock
|
|
);
|
|
|
|
VOID
|
|
Update_TotalStatisticsData(
|
|
IN FTPD_COUNTER_BLOCK * pCounterBlock,
|
|
OUT FTPD_COUNTER_BLOCK * pTotal
|
|
);
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: OpenFtpPerformanceData
|
|
|
|
SYNOPSIS: Initializes the data structures used to communicate
|
|
performance counters with the registry.
|
|
|
|
ENTRY: lpDeviceNames - Poitner to object ID of each device
|
|
to be opened.
|
|
|
|
RETURNS: DWORD - Win32 status code.
|
|
|
|
HISTORY:
|
|
KeithMo 07-Jun-1993 Created.
|
|
|
|
********************************************************************/
|
|
DWORD OpenFtpPerformanceData( LPWSTR lpDeviceNames )
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
HKEY hkey = NULL;
|
|
DWORD size;
|
|
DWORD type;
|
|
DWORD dwFirstCounter;
|
|
DWORD dwFirstHelp;
|
|
PERF_COUNTER_DEFINITION * pctr;
|
|
FTPD_COUNTER_BLOCK ftpc;
|
|
DWORD i;
|
|
|
|
//
|
|
// Since WINLOGON is multi-threaded and will call this routine in
|
|
// order to service remote performance queries, this library
|
|
// must keep track of how many times it has been opened (i.e.
|
|
// how many threads have accessed it). The registry routines will
|
|
// limit access to the initialization routine to only one thread
|
|
// at a time so synchronization (i.e. reentrancy) should not be
|
|
// a problem.
|
|
//
|
|
|
|
if( !fInitOK )
|
|
{
|
|
|
|
//
|
|
// This is the *first* open.
|
|
//
|
|
|
|
// open event log interface
|
|
|
|
if (hEventLog == NULL){
|
|
hEventLog = RegisterEventSource ((LPTSTR)NULL, // Use Local Machine
|
|
APP_NAME); // event log app name to find in registry
|
|
if (hEventLog == NULL)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open the FTP Server service's Performance key.
|
|
//
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
FTPD_PERFORMANCE_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&hkey );
|
|
|
|
if( err == NO_ERROR )
|
|
{
|
|
//
|
|
// Read the first counter DWORD.
|
|
//
|
|
|
|
size = sizeof(DWORD);
|
|
|
|
err = RegQueryValueEx( hkey,
|
|
"First Counter",
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)&dwFirstCounter,
|
|
&size );
|
|
if( err == NO_ERROR )
|
|
{
|
|
//
|
|
// Read the first help DWORD.
|
|
//
|
|
|
|
size = sizeof(DWORD);
|
|
|
|
err = RegQueryValueEx( hkey,
|
|
"First Help",
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)&dwFirstHelp,
|
|
&size );
|
|
|
|
if ( err == NO_ERROR )
|
|
{
|
|
//
|
|
// Update the object & counter name & help indicies.
|
|
//
|
|
|
|
FtpdDataDefinition.FtpdObjectType.ObjectNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdObjectType.ObjectHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
|
|
FtpdDataDefinition.FtpdBytesSent.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdBytesSent.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdBytesSent.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.BytesSent - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdBytesReceived.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdBytesReceived.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdBytesReceived.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.BytesReceived - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdBytesTotal.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdBytesTotal.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdBytesTotal.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.BytesTotal - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdFilesSent.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdFilesSent.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdFilesSent.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.FilesSent - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdFilesReceived.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdFilesReceived.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdFilesReceived.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.FilesReceived - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdFilesTotal.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdFilesTotal.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdFilesTotal.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.FilesTotal - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdCurrentAnonymous.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdCurrentAnonymous.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdCurrentAnonymous.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.CurrentAnonymous - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdCurrentNonAnonymous.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdCurrentNonAnonymous.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdCurrentNonAnonymous.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.CurrentNonAnonymous - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdTotalAnonymous.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdTotalAnonymous.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdTotalAnonymous.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.TotalAnonymous - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdTotalNonAnonymous.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdTotalNonAnonymous.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdTotalNonAnonymous.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.TotalNonAnonymous - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdMaxAnonymous.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdMaxAnonymous.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdMaxAnonymous.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.MaxAnonymous - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdMaxNonAnonymous.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdMaxNonAnonymous.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdMaxNonAnonymous.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.MaxNonAnonymous - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdCurrentConnections.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdCurrentConnections.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdCurrentConnections.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.CurrentConnections - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdMaxConnections.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdMaxConnections.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdMaxConnections.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.MaxConnections - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdConnectionAttempts.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdConnectionAttempts.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdConnectionAttempts.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.ConnectionAttempts - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdLogonAttempts.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdLogonAttempts.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdLogonAttempts.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.LogonAttempts - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdServiceUptime.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdServiceUptime.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdServiceUptime.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.ServiceUptime - (LPBYTE)&ftpc);
|
|
|
|
// These counters are currently meaningless, but should be restored if we
|
|
// ever enable per-FTP-instance bandwidth throttling.
|
|
/*
|
|
FtpdDataDefinition.FtpdBlockedRequests.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdBlockedRequests.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdBlockedRequests.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.BlockedRequests - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdAllowedRequests.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdAllowedRequests.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdAllowedRequests.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.AllowedRequests - (LPBYTE)&ftpc);
|
|
|
|
|
|
FtpdDataDefinition.FtpdRejectedRequests.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdRejectedRequests.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdRejectedRequests.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.RejectedRequests - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdCurrentBlockedRequests.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdCurrentBlockedRequests.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdCurrentBlockedRequests.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.CurrentBlockedRequests - (LPBYTE)&ftpc);
|
|
|
|
FtpdDataDefinition.FtpdMeasuredBandwidth.CounterNameTitleIndex
|
|
+= dwFirstCounter;
|
|
FtpdDataDefinition.FtpdMeasuredBandwidth.CounterHelpTitleIndex
|
|
+= dwFirstHelp;
|
|
FtpdDataDefinition.FtpdMeasuredBandwidth.CounterOffset =
|
|
(DWORD)((LPBYTE)&ftpc.MeasuredBandwidth - (LPBYTE)&ftpc);
|
|
|
|
*/
|
|
|
|
//
|
|
// Remember that we initialized OK.
|
|
//
|
|
|
|
fInitOK = TRUE;
|
|
} else {
|
|
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
|
|
0, FTP_UNABLE_QUERY_DATA,
|
|
(PSID)NULL, 0,
|
|
sizeof(err), NULL,
|
|
(PVOID)(&err));
|
|
}
|
|
} else {
|
|
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
|
|
0, FTP_UNABLE_QUERY_DATA,
|
|
(PSID)NULL, 0,
|
|
sizeof(err), NULL,
|
|
(PVOID)(&err));
|
|
}
|
|
|
|
//
|
|
// Close the registry if we managed to actually open it.
|
|
//
|
|
|
|
if( hkey != NULL )
|
|
{
|
|
RegCloseKey( hkey );
|
|
hkey = NULL;
|
|
}
|
|
} else {
|
|
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
|
|
0, FTP_UNABLE_QUERY_DATA,
|
|
(PSID)NULL, 0,
|
|
sizeof(err), NULL,
|
|
(PVOID)(&err));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bump open counter.
|
|
//
|
|
|
|
InterlockedIncrement((LPLONG )&cOpens);
|
|
|
|
return err;
|
|
|
|
} // OpenFTPPerformanceData
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CollectFtpPerformanceData
|
|
|
|
SYNOPSIS: Initializes the data structures used to communicate
|
|
|
|
ENTRY: lpValueName - The name of the value to retrieve.
|
|
|
|
lppData - On entry contains a pointer to the buffer to
|
|
receive the completed PerfDataBlock & subordinate
|
|
structures. On exit, points to the first bytes
|
|
*after* the data structures added by this routine.
|
|
|
|
lpcbTotalBytes - On entry contains a pointer to the
|
|
size (in BYTEs) of the buffer referenced by lppData.
|
|
On exit, contains the number of BYTEs added by this
|
|
routine.
|
|
|
|
lpNumObjectTypes - Receives the number of objects added
|
|
by this routine.
|
|
|
|
RETURNS: DWORD - Win32 status code. MUST be either NO_ERROR
|
|
or ERROR_MORE_DATA.
|
|
|
|
HISTORY:
|
|
KeithMo 07-Jun-1993 Created.
|
|
|
|
********************************************************************/
|
|
DWORD CollectFtpPerformanceData( LPWSTR lpValueName,
|
|
LPVOID * lppData,
|
|
LPDWORD lpcbTotalBytes,
|
|
LPDWORD lpNumObjectTypes )
|
|
{
|
|
PERF_INSTANCE_DEFINITION * pPerfInstanceDefinition;
|
|
DWORD dwInstanceIndex = 0;
|
|
DWORD dwInstanceCount = 0;
|
|
DWORD i = 0;
|
|
DWORD dwQueryType;
|
|
ULONG cbRequired;
|
|
DWORD * pdwCounter;
|
|
LARGE_INTEGER * pliCounter;
|
|
FTPD_COUNTER_BLOCK * pCounterBlock;
|
|
FTPD_COUNTER_BLOCK * pTotal;
|
|
FTPD_DATA_DEFINITION * pFtpdDataDefinition;
|
|
FTP_STATISTICS_0 * pFTPStats;
|
|
NET_API_STATUS neterr;
|
|
HRESULT hresErr;
|
|
DWORD dwBufferSize = 0;
|
|
|
|
LPINET_INFO_SITE_LIST pSites;
|
|
|
|
|
|
//
|
|
// No need to even try if we failed to open...
|
|
//
|
|
|
|
if( !fInitOK )
|
|
{
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
//
|
|
// According to the Performance Counter design, this
|
|
// is a successful exit. Go figure.
|
|
//
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Determine the query type.
|
|
//
|
|
|
|
dwQueryType = GetQueryType( lpValueName );
|
|
|
|
if (( dwQueryType == QUERY_FOREIGN ) || (dwQueryType == QUERY_COSTLY))
|
|
{
|
|
//
|
|
// We don't do foreign queries.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if( dwQueryType == QUERY_ITEMS )
|
|
{
|
|
//
|
|
// The registry is asking for a specific object. Let's
|
|
// see if we're one of the chosen.
|
|
//
|
|
|
|
if( !IsNumberInUnicodeList(
|
|
FtpdDataDefinition.FtpdObjectType.ObjectNameTitleIndex,
|
|
lpValueName ) )
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enumerate and get total number of instances count.
|
|
//
|
|
pFtpdDataDefinition = (FTPD_DATA_DEFINITION *)*lppData;
|
|
|
|
neterr = InetInfoGetSites(
|
|
NULL,
|
|
INET_FTP_SVC_ID,
|
|
&pSites
|
|
);
|
|
|
|
|
|
if( neterr != NERR_Success )
|
|
{
|
|
|
|
//
|
|
// Only event log once for each server down
|
|
//
|
|
|
|
// if the server is down, we don't log an error.
|
|
if ( !( neterr == RPC_S_SERVER_UNAVAILABLE ||
|
|
neterr == RPC_S_UNKNOWN_IF ||
|
|
neterr == ERROR_SERVICE_NOT_ACTIVE ||
|
|
neterr == RPC_S_CALL_FAILED_DNE ))
|
|
{
|
|
//
|
|
// Error retrieving statistics.
|
|
//
|
|
|
|
ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE,
|
|
0, FTP_UNABLE_QUERY_DATA,
|
|
(PSID)NULL, 0,
|
|
sizeof(neterr), NULL,
|
|
(PVOID)(&neterr));
|
|
|
|
}
|
|
|
|
cbRequired = sizeof(FTPD_DATA_DEFINITION) +
|
|
sizeof(PERF_INSTANCE_DEFINITION) +
|
|
(sizeof(WCHAR) * MAX_SIZEOF_INSTANCE_NAME ) +
|
|
sizeof(FTPD_COUNTER_BLOCK);
|
|
|
|
if( *lpcbTotalBytes < cbRequired )
|
|
{
|
|
//
|
|
// Nope.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
// We always return the _Total instance even if the counters
|
|
// are not accessible. This is so we stay in sync with how the
|
|
// other IIS counters work. For the PERF_NO_INSTANCE counters we need
|
|
// to do this so that WMI get's it's definition data even if the service
|
|
// is not running, and logging doesn't get confused by a PERF_NO_INSTANCE
|
|
// counter returning zero instances.
|
|
|
|
// First we move in the definition.
|
|
memmove( pFtpdDataDefinition,
|
|
&FtpdDataDefinition,
|
|
sizeof(FTPD_DATA_DEFINITION) );
|
|
|
|
((PERF_OBJECT_TYPE*) pFtpdDataDefinition)->NumInstances = 1;
|
|
((PERF_OBJECT_TYPE*) pFtpdDataDefinition)->TotalByteLength = cbRequired;
|
|
|
|
LPVOID pData = (LPVOID) ( pFtpdDataDefinition + 1 );
|
|
|
|
// Now we setup the PERF_INSTANCE_DEFINITION
|
|
((PERF_INSTANCE_DEFINITION*) pData)->ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
|
|
MAX_SIZEOF_INSTANCE_NAME * sizeof(WCHAR);
|
|
((PERF_INSTANCE_DEFINITION*) pData)->ParentObjectTitleIndex = 0;
|
|
((PERF_INSTANCE_DEFINITION*) pData)->ParentObjectInstance = 0;
|
|
((PERF_INSTANCE_DEFINITION*) pData)->UniqueID = PERF_NO_UNIQUE_ID;
|
|
((PERF_INSTANCE_DEFINITION*) pData)->NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
|
|
((PERF_INSTANCE_DEFINITION*) pData)->NameLength = (wcslen(TOTAL_INSTANCE_NAME) + 1) * sizeof(WCHAR);
|
|
|
|
pData = (LPBYTE) pData + sizeof(PERF_INSTANCE_DEFINITION);
|
|
|
|
// Next copy in the Instance Name including the
|
|
// NULL, we know we have enough room because of
|
|
// the check above for size.
|
|
wcsncpy ( (LPWSTR) pData, TOTAL_INSTANCE_NAME, wcslen(TOTAL_INSTANCE_NAME) + 1 );
|
|
|
|
// To avoid suttle differences we use the same MAX_INSTANCE_NAME
|
|
// amount of space even for this faked up _Total Site.
|
|
pData = (LPBYTE) pData + ( MAX_SIZEOF_INSTANCE_NAME * sizeof(WCHAR));
|
|
|
|
// Lastly copy in a block of zero's for the _Total site data.
|
|
memset ( pData, 0, sizeof(FTPD_COUNTER_BLOCK) );
|
|
|
|
// This is setting the size in the structure, it is the first
|
|
// DWORD in the W3_CONTER_BLOCK.
|
|
*((DWORD*) (pData)) = sizeof(FTPD_COUNTER_BLOCK);
|
|
|
|
*lpcbTotalBytes = cbRequired;
|
|
*lpNumObjectTypes = 1;
|
|
*lppData = (LPBYTE) pFtpdDataDefinition + cbRequired;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// add 1 to dwInstanceCount for _Total instance
|
|
//
|
|
|
|
dwInstanceCount = pSites->cEntries + 1;
|
|
|
|
//
|
|
// always return an "instance sized" buffer after the definition
|
|
// blocks to prevent perfmon from reading bogus data. This is strictly
|
|
// a hack to accomodate how PERFMON handles the "0" instance case.
|
|
// By doing this, perfmon won't choke when there are no instances
|
|
// and the counter object & counters will be displayed in the list
|
|
// boxes, even though no instances will be listed.
|
|
//
|
|
|
|
cbRequired = sizeof(FTPD_DATA_DEFINITION) +
|
|
(dwInstanceCount * (sizeof(PERF_INSTANCE_DEFINITION) +
|
|
MAX_SIZEOF_INSTANCE_NAME +
|
|
sizeof (FTPD_COUNTER_BLOCK)));
|
|
|
|
//
|
|
// See if there's enough space.
|
|
//
|
|
|
|
if( *lpcbTotalBytes < cbRequired )
|
|
{
|
|
//
|
|
// Nope.
|
|
//
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
MIDL_user_free(pSites);
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Copy the (constant, initialized) Object Type and counter definitions
|
|
// to the caller's data buffer
|
|
//
|
|
|
|
memmove( pFtpdDataDefinition,
|
|
&FtpdDataDefinition,
|
|
sizeof(FTPD_DATA_DEFINITION) );
|
|
|
|
//
|
|
// Create data for return for each instance
|
|
//
|
|
|
|
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
|
|
&pFtpdDataDefinition[1];
|
|
|
|
//
|
|
// Set first block of Buffer for _Total
|
|
//
|
|
|
|
MonBuildInstanceDefinition(
|
|
pPerfInstanceDefinition,
|
|
(PVOID *)&pCounterBlock,
|
|
0,
|
|
0,
|
|
(DWORD)-1, // use name
|
|
TOTAL_INSTANCE_NAME ); // pass in instance name
|
|
|
|
pTotal = pCounterBlock;
|
|
memset( pTotal, 0, sizeof(FTPD_COUNTER_BLOCK ));
|
|
pTotal->PerfCounterBlock.ByteLength = sizeof (FTPD_COUNTER_BLOCK);
|
|
pPerfInstanceDefinition =
|
|
(PERF_INSTANCE_DEFINITION *)((LPBYTE)pCounterBlock +
|
|
sizeof(FTPD_COUNTER_BLOCK));
|
|
|
|
|
|
neterr = FtpQueryStatistics2(
|
|
NULL,
|
|
0,
|
|
0, // instance id, 0 for global stats
|
|
0,
|
|
(LPBYTE *)&pFTPStats );
|
|
|
|
if( neterr == NERR_Success )
|
|
{
|
|
pTotal->ServiceUptime = pFTPStats->ServiceUptime;
|
|
}
|
|
|
|
MIDL_user_free( pFTPStats );
|
|
|
|
for ( i = 0; i < pSites->cEntries; i++)
|
|
{
|
|
MonBuildInstanceDefinition(
|
|
pPerfInstanceDefinition,
|
|
(PVOID *)&pCounterBlock,
|
|
0,
|
|
0,
|
|
(DWORD)-1, // use name
|
|
pSites->aSiteEntry[i].pszComment // pass in instance name
|
|
);
|
|
|
|
//
|
|
// query for statistics info
|
|
//
|
|
|
|
neterr = FtpQueryStatistics2(
|
|
NULL,
|
|
0,
|
|
pSites->aSiteEntry[i].dwInstance, // instance id
|
|
0,
|
|
(LPBYTE *)&pFTPStats );
|
|
|
|
if( neterr != NERR_Success )
|
|
{
|
|
//
|
|
// Only event log once for each server down
|
|
//
|
|
|
|
// if the server is down, we don't log an error.
|
|
if ( !( neterr == RPC_S_SERVER_UNAVAILABLE ||
|
|
neterr == RPC_S_UNKNOWN_IF ||
|
|
neterr == ERROR_SERVICE_NOT_ACTIVE ||
|
|
neterr == RPC_S_CALL_FAILED_DNE ))
|
|
{
|
|
//
|
|
// Error retrieving statistics.
|
|
//
|
|
ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
|
|
0, FTP_UNABLE_QUERY_DATA,
|
|
(PSID)NULL, 0,
|
|
sizeof(neterr), NULL,
|
|
(PVOID)(&neterr));
|
|
}
|
|
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
|
|
MIDL_user_free(pSites);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Format the FTP Server data.
|
|
//
|
|
|
|
CopyStatisticsData( pFTPStats,
|
|
pCounterBlock );
|
|
|
|
//
|
|
// update _total instance counters
|
|
//
|
|
|
|
Update_TotalStatisticsData( pCounterBlock,
|
|
pTotal );
|
|
|
|
pPerfInstanceDefinition =
|
|
(PERF_INSTANCE_DEFINITION *)((LPBYTE)pCounterBlock +
|
|
sizeof(FTPD_COUNTER_BLOCK));
|
|
|
|
//
|
|
// Free the API buffer.
|
|
//
|
|
|
|
MIDL_user_free( pFTPStats );
|
|
}
|
|
|
|
if (dwInstanceCount == 1) {
|
|
DWORD cbSize = sizeof(PERF_INSTANCE_DEFINITION) +
|
|
MAX_SIZEOF_INSTANCE_NAME +
|
|
sizeof(FTPD_COUNTER_BLOCK);
|
|
|
|
//
|
|
// zero fill one instance sized block of data if there's no data
|
|
// instances
|
|
//
|
|
|
|
memset (pPerfInstanceDefinition, 0, cbSize);
|
|
|
|
// adjust pointer to point to end of zeroed block
|
|
pPerfInstanceDefinition += cbSize;
|
|
}
|
|
|
|
//
|
|
// Update arguments for return.
|
|
//
|
|
|
|
*lppData = (PVOID)(pPerfInstanceDefinition);
|
|
|
|
*lpNumObjectTypes = 1;
|
|
|
|
pFtpdDataDefinition->FtpdObjectType.NumInstances = dwInstanceCount;
|
|
|
|
pFtpdDataDefinition->FtpdObjectType.TotalByteLength =
|
|
*lpcbTotalBytes = DIFF((PBYTE)pPerfInstanceDefinition -
|
|
(PBYTE)pFtpdDataDefinition);
|
|
|
|
//
|
|
// Success! Honest!!
|
|
//
|
|
|
|
MIDL_user_free(pSites);
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CollectFTPPerformanceData
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CloseFtpPerformanceData
|
|
|
|
SYNOPSIS: Terminates the performance counters.
|
|
|
|
RETURNS: DWORD - Win32 status code.
|
|
|
|
HISTORY:
|
|
KeithMo 07-Jun-1993 Created.
|
|
|
|
********************************************************************/
|
|
DWORD CloseFtpPerformanceData( VOID )
|
|
{
|
|
|
|
DWORD dwCount = InterlockedDecrement((LPLONG )&cOpens);
|
|
|
|
if ((dwCount) == 0) {
|
|
if (hEventLog != NULL)
|
|
{
|
|
DeregisterEventSource (hEventLog);
|
|
hEventLog = NULL;
|
|
};
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CloseFTPPerformanceData
|
|
|
|
|
|
VOID
|
|
CopyStatisticsData(
|
|
IN FTP_STATISTICS_0 * pFTPStats,
|
|
OUT FTPD_COUNTER_BLOCK * pCounterBlock
|
|
)
|
|
{
|
|
//
|
|
// Format the FTP Server data.
|
|
//
|
|
|
|
pCounterBlock->PerfCounterBlock.ByteLength = sizeof (FTPD_COUNTER_BLOCK);
|
|
|
|
pCounterBlock->BytesSent = pFTPStats->TotalBytesSent.QuadPart;
|
|
pCounterBlock->BytesReceived = pFTPStats->TotalBytesReceived.QuadPart;
|
|
pCounterBlock->BytesTotal = pFTPStats->TotalBytesSent.QuadPart +
|
|
pFTPStats->TotalBytesReceived.QuadPart;
|
|
|
|
pCounterBlock->FilesSent = pFTPStats->TotalFilesSent;
|
|
pCounterBlock->FilesReceived = pFTPStats->TotalFilesReceived;
|
|
pCounterBlock->FilesTotal = pFTPStats->TotalFilesSent +
|
|
pFTPStats->TotalFilesReceived;
|
|
|
|
pCounterBlock->CurrentAnonymous = pFTPStats->CurrentAnonymousUsers;
|
|
pCounterBlock->CurrentNonAnonymous = pFTPStats->CurrentNonAnonymousUsers;
|
|
|
|
pCounterBlock->TotalAnonymous = pFTPStats->TotalAnonymousUsers;
|
|
pCounterBlock->TotalNonAnonymous = pFTPStats->TotalNonAnonymousUsers;
|
|
|
|
pCounterBlock->MaxAnonymous = pFTPStats->MaxAnonymousUsers;
|
|
pCounterBlock->MaxNonAnonymous = pFTPStats->MaxNonAnonymousUsers;
|
|
|
|
pCounterBlock->CurrentConnections = pFTPStats->CurrentConnections;
|
|
pCounterBlock->MaxConnections = pFTPStats->MaxConnections;
|
|
pCounterBlock->ConnectionAttempts = pFTPStats->ConnectionAttempts;
|
|
|
|
pCounterBlock->LogonAttempts = pFTPStats->LogonAttempts;
|
|
|
|
pCounterBlock->ServiceUptime = pFTPStats->ServiceUptime;
|
|
|
|
// These counters are currently meaningless, but should be restored if we
|
|
// ever enable per-FTP-instance bandwidth throttling.
|
|
/*
|
|
pCounterBlock->BlockedRequests = pFTPStats->TotalBlockedRequests;
|
|
pCounterBlock->AllowedRequests = pFTPStats->TotalAllowedRequests;
|
|
pCounterBlock->RejectedRequests = pFTPStats->TotalRejectedRequests;
|
|
pCounterBlock->MeasuredBandwidth= pFTPStats->MeasuredBandwidth;
|
|
pCounterBlock->CurrentBlockedRequests = pFTPStats->CurrentBlockedRequests;
|
|
*/
|
|
} // CopyStatisticsData
|
|
|
|
|
|
VOID
|
|
Update_TotalStatisticsData(
|
|
IN FTPD_COUNTER_BLOCK * pCounterBlock,
|
|
OUT FTPD_COUNTER_BLOCK * pTotal
|
|
)
|
|
{
|
|
//
|
|
// update _total instance counters
|
|
//
|
|
|
|
pTotal->BytesSent += pCounterBlock->BytesSent;
|
|
pTotal->BytesReceived += pCounterBlock->BytesReceived;
|
|
pTotal->BytesTotal += pCounterBlock->BytesTotal;
|
|
|
|
pTotal->FilesSent += pCounterBlock->FilesSent;
|
|
pTotal->FilesReceived += pCounterBlock->FilesReceived;
|
|
pTotal->FilesTotal += pCounterBlock->FilesTotal;
|
|
pTotal->CurrentAnonymous += pCounterBlock->CurrentAnonymous;
|
|
pTotal->CurrentNonAnonymous += pCounterBlock->CurrentNonAnonymous;
|
|
pTotal->TotalAnonymous += pCounterBlock->TotalAnonymous;
|
|
pTotal->TotalNonAnonymous += pCounterBlock->TotalNonAnonymous;
|
|
|
|
pTotal->MaxAnonymous += pCounterBlock->MaxAnonymous;
|
|
pTotal->MaxNonAnonymous += pCounterBlock->MaxNonAnonymous;
|
|
|
|
pTotal->CurrentConnections += pCounterBlock->CurrentConnections;
|
|
pTotal->MaxConnections += pCounterBlock->MaxConnections;
|
|
pTotal->ConnectionAttempts = pCounterBlock->ConnectionAttempts;
|
|
|
|
pTotal->LogonAttempts += pCounterBlock->LogonAttempts;
|
|
|
|
// These counters are currently meaningless, but should be restored if we
|
|
// ever enable per-FTP-instance bandwidth throttling.
|
|
/*
|
|
pTotal->BlockedRequests += pCounterBlock->BlockedRequests;
|
|
pTotal->RejectedRequests += pCounterBlock->RejectedRequests;
|
|
pTotal->AllowedRequests += pCounterBlock->AllowedRequests;
|
|
pTotal->MeasuredBandwidth += pCounterBlock->MeasuredBandwidth;
|
|
pTotal->CurrentBlockedRequests += pCounterBlock->CurrentBlockedRequests;
|
|
*/
|
|
|
|
} // Update_TotalStatisticsData
|