/**********************************************************************/ /** Microsoft Windows NT **/ /** Copyright(c) Microsoft Corp., 1993 **/ /**********************************************************************/ /* perfwins.c 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. */ #include #include #include #include #include #include #include #include #include "winsctrs.h" #include "perfmsg.h" #include "perfutil.h" #include "winsintf.h" #include "winsdata.h" #include "debug.h" #include "winsevnt.h" // // Private globals. // DWORD cOpens = 0; // Active "opens" reference count. BOOL fInitOK = FALSE; // TRUE if DLL initialized OK. BOOL sfLogOpen; //indicates whether the log is //open or closed BOOL sfErrReported; //to prevent the same error from being //logged continuously #if DBG DWORD WinsdDebug = 0; // Debug behaviour flags. #endif // DBG // // Public prototypes. // PM_OPEN_PROC OpenWinsPerformanceData; PM_COLLECT_PROC CollectWinsPerformanceData; PM_CLOSE_PROC CloseWinsPerformanceData; // // Public functions. // /******************************************************************* NAME: OpenWinsPerformanceData 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: Pradeepb 20-July-1993 Created. ********************************************************************/ DWORD OpenWinsPerformanceData( LPWSTR lpDeviceNames ) { DWORD err = NO_ERROR; HKEY hkey = NULL; // DWORD size; // DWORD type; DWORD dwFirstCounter; DWORD dwFirstHelp; IF_DEBUG( ENTRYPOINTS ) { WINSD_PRINT(( "in OpenWinsPerformanceData\n" )); } // // Since SCREG 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 ) { PERF_COUNTER_DEFINITION * pctr; DWORD i; if(AddSrcToReg() == ERROR_SUCCESS) { if (!MonOpenEventLog()) { sfLogOpen = TRUE; } } // // This is the *first* open. // dwFirstCounter = WINSCTRS_FIRST_COUNTER; dwFirstHelp = WINSCTRS_FIRST_HELP; // // Update the object & counter name & help indicies. // WinsDataDataDefinition.ObjectType.ObjectNameTitleIndex += dwFirstCounter; WinsDataDataDefinition.ObjectType.ObjectHelpTitleIndex += dwFirstHelp; pctr = &WinsDataDataDefinition.UniqueReg; for( i = 0 ; i < NUMBER_OF_WINSDATA_COUNTERS ; i++ ) { pctr->CounterNameTitleIndex += dwFirstCounter; pctr->CounterHelpTitleIndex += dwFirstHelp; pctr++; } // // Remember that we initialized OK. // fInitOK = TRUE; // // Close the registry if we managed to actually open it. // if( hkey != NULL ) { RegCloseKey( hkey ); hkey = NULL; } IF_DEBUG( OPEN ) { if( err != NO_ERROR ) { WINSD_PRINT(( "Cannot read registry data, error %lu\n", err )); } } } // // Bump open counter. // if( err == NO_ERROR ) { cOpens++; } // // if sfLogOpen is FALSE, it means that all threads we closed the // event log in CloseWinsPerformanceData // if (!sfLogOpen) { MonOpenEventLog(); } return err; } // OpenWinsPerformanceData /******************************************************************* NAME: CollectWinsPerformanceData 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 CollectWinsPerformanceData( LPWSTR lpValueName, LPVOID * lppData, LPDWORD lpcbTotalBytes, LPDWORD lpNumObjectTypes ) { DWORD dwQueryType; ULONG cbRequired; DWORD *pdwCounter; WINSDATA_COUNTER_BLOCK *pCounterBlock; WINSDATA_DATA_DEFINITION *pWinsDataDataDefinition; WINSINTF_RESULTS_NEW_T Results; #if 0 WINSINTF_RESULTS_T Results; #endif WINSINTF_STAT_T *pWinsStats = &Results.WinsStat; DWORD Status; IF_DEBUG( ENTRYPOINTS ) { WINSD_PRINT(( "in CollectWinsPerformanceData\n" )); WINSD_PRINT(( " lpValueName = %08lX (%ls)\n", lpValueName, lpValueName )); WINSD_PRINT(( " lppData = %08lX (%08lX)\n", lppData, *lppData )); WINSD_PRINT(( " lpcbTotalBytes = %08lX (%08lX)\n", lpcbTotalBytes, *lpcbTotalBytes )); WINSD_PRINT(( " lpNumObjectTypes = %08lX (%08lX)\n", lpNumObjectTypes, *lpNumObjectTypes )); } // // No need to even try if we failed to open... // if( !fInitOK ) { IF_DEBUG( COLLECT ) { WINSD_PRINT(( "Initialization failed, CollectWinsPerformanceData aborting\n" )); } *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 ) { IF_DEBUG( COLLECT ) { WINSD_PRINT(( "foreign queries not supported\n" )); } // // 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( WinsDataDataDefinition.ObjectType.ObjectNameTitleIndex, lpValueName ) ) { IF_DEBUG( COLLECT ) { WINSD_PRINT(( "%ls not a supported object type\n", lpValueName )); } *lpcbTotalBytes = 0; *lpNumObjectTypes = 0; return NO_ERROR; } } // // See if there's enough space. // pWinsDataDataDefinition = (WINSDATA_DATA_DEFINITION *)*lppData; cbRequired = sizeof(WINSDATA_DATA_DEFINITION) + WINSDATA_SIZE_OF_PERFORMANCE_DATA; if( *lpcbTotalBytes < cbRequired ) { IF_DEBUG( COLLECT ) { WINSD_PRINT(( "%lu bytes of buffer insufficient, %lu needed\n", *lpcbTotalBytes, cbRequired )); } // // Nope. // *lpcbTotalBytes = 0; *lpNumObjectTypes = 0; return ERROR_MORE_DATA; } // // Copy the (constant, initialized) Object Type and counter definitions // to the caller's data buffer // memmove( pWinsDataDataDefinition, &WinsDataDataDefinition, sizeof(WINSDATA_DATA_DEFINITION) ); // // Try to retrieve the data. // Results.WinsStat.NoOfPnrs = 0; Results.WinsStat.pRplPnrs = NULL; Results.pAddVersMaps = NULL; { WINSINTF_BIND_DATA_T BindData; handle_t BindHdl; BindData.fTcpIp = FALSE; BindData.pPipeName = (LPBYTE)TEXT("\\pipe\\WinsPipe"); BindData.pServerAdd = (LPBYTE)TEXT(""); BindHdl = WinsBind(&BindData); Status = WinsStatusNew(BindHdl, WINSINTF_E_STAT, &Results); WinsUnbind(&BindData, BindHdl); } if( Status != WINSINTF_SUCCESS ) { IF_DEBUG( COLLECT ) { WINSD_PRINT(( "cannot retrieve statistics, error %lu\n", Status )); } // // if we haven't logged the error yet, log it // if (!sfErrReported) { REPORT_ERROR(WINS_EVT_WINS_STATUS_ERR, LOG_USER); sfErrReported = TRUE; } // // Error retrieving statistics. // *lpcbTotalBytes = 0; *lpNumObjectTypes = 0; return NO_ERROR; } // // Ahaa, we got the statistics, reset flag if set // if (sfErrReported) { sfErrReported = FALSE; } // // Format the WINS Server data. // pCounterBlock = (WINSDATA_COUNTER_BLOCK *)( pWinsDataDataDefinition + 1 ); pCounterBlock->PerfCounterBlock.ByteLength = WINSDATA_SIZE_OF_PERFORMANCE_DATA; // // Get the pointer to the first (DWORD) counter. This // pointer *must* be quadword aligned. // pdwCounter = (DWORD *)( pCounterBlock + 1 ); WINSD_ASSERT( ( (DWORD_PTR)pdwCounter & 3 ) == 0 ); IF_DEBUG( COLLECT ) { WINSD_PRINT(( "pWinsDataDataDefinition = %08lX\n", pWinsDataDataDefinition )); WINSD_PRINT(( "pCounterBlock = %08lX\n", pCounterBlock )); WINSD_PRINT(( "ByteLength = %08lX\n", pCounterBlock->PerfCounterBlock.ByteLength )); WINSD_PRINT(( "pliCounter = %08lX\n", pdwCounter )); } // // Move the DWORDs into the buffer. // IF_DEBUG( COLLECT ) { WINSD_PRINT(( "pdwCounter = %08lX\n", pdwCounter )); } *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfUniqueReg; *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfGroupReg; *pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfUniqueReg + pWinsStats->Counters.NoOfGroupReg); *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfUniqueRef; *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfGroupRef; *pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfUniqueRef + pWinsStats->Counters.NoOfGroupRef); *pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfSuccRel + pWinsStats->Counters.NoOfFailRel); *pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfSuccQueries + pWinsStats->Counters.NoOfFailQueries); *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfUniqueCnf; *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfGroupCnf; *pdwCounter++ = (DWORD)(pWinsStats->Counters.NoOfUniqueCnf + pWinsStats->Counters.NoOfGroupCnf); *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfSuccRel; *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfFailRel; *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfSuccQueries; *pdwCounter++ = (DWORD)pWinsStats->Counters.NoOfFailQueries; // // Update arguments for return. // *lppData = (PVOID)pdwCounter; *lpNumObjectTypes = 1; *lpcbTotalBytes = (DWORD)((BYTE *)pdwCounter - (BYTE *)pWinsDataDataDefinition); IF_DEBUG( COLLECT ) { WINSD_PRINT(( "pData = %08lX\n", *lppData )); WINSD_PRINT(( "NumObjectTypes = %08lX\n", *lpNumObjectTypes )); WINSD_PRINT(( "cbTotalBytes = %08lX\n", *lpcbTotalBytes )); } // // Free the API buffer. // #if 0 NetApiBufferFree( (LPBYTE)pWinsStats ); #endif // // Free the buffers RPC allocates. // WinsFreeMem( Results.pAddVersMaps ); WinsFreeMem( Results.WinsStat.pRplPnrs ); // // Success! Honest!! // return NO_ERROR; } // CollectWinsPerformanceData /******************************************************************* NAME: CloseWinsPerformanceData SYNOPSIS: Terminates the performance counters. RETURNS: DWORD - Win32 status code. HISTORY: KeithMo 07-Jun-1993 Created. ********************************************************************/ DWORD CloseWinsPerformanceData( VOID ) { IF_DEBUG( ENTRYPOINTS ) { WINSD_PRINT(( "in CloseWinsPerformanceData\n" )); } // // No real cleanup to do here. // cOpens--; if (!cOpens) { // // unbind from the nameserver. There could be synch. problems since // sfLogOpen is changed in both Open and Close functions. This at the // max. will affect logging. It being unclear at this point whether or // not Open gets called multiple times (from all looks of it, it is only // called once), this flag may even not be necessary. // MonCloseEventLog(); sfLogOpen = FALSE; } return NO_ERROR; } // CloseWinsPerformanceData