/**********************************************************************/ /** 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 #include #include #include #include #include #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. // 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)); } *lpcbTotalBytes = 0; *lpNumObjectTypes = 0; 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. // pFtpdDataDefinition = (FTPD_DATA_DEFINITION *)*lppData; 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) { // // zero fill one instance sized block of data if there's no data // instances // memset (pPerfInstanceDefinition, 0, (sizeof(PERF_INSTANCE_DEFINITION) + MAX_SIZEOF_INSTANCE_NAME + sizeof(FTPD_COUNTER_BLOCK))); // adjust pointer to point to end of zeroed block pPerfInstanceDefinition += (sizeof(PERF_INSTANCE_DEFINITION) + MAX_SIZEOF_INSTANCE_NAME + sizeof(FTPD_COUNTER_BLOCK)); } // // 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