Leaked source code of windows server 2003
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.

545 lines
16 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. infoperf.c
  7. This file implements the Extensible Performance Objects for
  8. the common INFO counters
  9. FILE HISTORY:
  10. KeithMo 07-Jun-1993 Created, based on RussBl's sample code.
  11. MuraliK 02-Jun-1995 Added Counters for Atq I/O requests
  12. SophiaC 16-Oct-1995 Info/Access Product Split
  13. MuraliK 16-Nov-1995 Removed undoc apis
  14. */
  15. #include <windows.h>
  16. #include <winperf.h>
  17. #include <lm.h>
  18. #include <inetinfo.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <infoctrs.h>
  22. #include <infodata.h>
  23. #include <perfutil.h>
  24. #include <iis64.h>
  25. #include "infomsg.h"
  26. # include "apiutil.h"
  27. //
  28. // Private constants.
  29. //
  30. #define APP_NAME (TEXT("IISInfoCtrs"))
  31. //
  32. // Private globals.
  33. //
  34. DWORD cOpens = 0; // Active "opens" reference count.
  35. BOOL fInitOK = FALSE; // TRUE if DLL initialized OK.
  36. HANDLE hEventLog = NULL; // event log handle
  37. #if DBG
  38. DWORD INFODebug = 0; // Debug behaviour flags.
  39. #endif // DBG
  40. //
  41. // Public prototypes.
  42. //
  43. PM_OPEN_PROC OpenINFOPerformanceData;
  44. PM_COLLECT_PROC CollectINFOPerformanceData;
  45. PM_CLOSE_PROC CloseINFOPerformanceData;
  46. //
  47. // Public functions.
  48. //
  49. /*******************************************************************
  50. NAME: OpenINFOPerformanceData
  51. SYNOPSIS: Initializes the data structures used to communicate
  52. performance counters with the registry.
  53. ENTRY: lpDeviceNames - Poitner to object ID of each device
  54. to be opened.
  55. RETURNS: DWORD - Win32 status code.
  56. HISTORY:
  57. KeithMo 07-Jun-1993 Created.
  58. ********************************************************************/
  59. DWORD OpenINFOPerformanceData( LPWSTR lpDeviceNames )
  60. {
  61. DWORD err = NO_ERROR;
  62. HKEY hkey = NULL;
  63. DWORD size;
  64. DWORD type;
  65. DWORD dwFirstCounter;
  66. DWORD dwFirstHelp;
  67. PERF_COUNTER_DEFINITION * pctr;
  68. DWORD i;
  69. //
  70. // Since SCREG is multi-threaded and will call this routine in
  71. // order to service remote performance queries, this library
  72. // must keep track of how many times it has been opened (i.e.
  73. // how many threads have accessed it). The registry routines will
  74. // limit access to the initialization routine to only one thread
  75. // at a time so synchronization (i.e. reentrancy) should not be
  76. // a problem.
  77. //
  78. if( !fInitOK )
  79. {
  80. //
  81. // This is the *first* open.
  82. //
  83. // open the event log interface
  84. if (hEventLog == NULL) {
  85. hEventLog = RegisterEventSource (
  86. (LPSTR)NULL, // on the local machine
  87. APP_NAME); // register the name to allow message lookup
  88. }
  89. //
  90. // Open the HTTP Server service's Performance key.
  91. //
  92. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  93. INFO_PERFORMANCE_KEY,
  94. 0,
  95. KEY_READ,
  96. &hkey );
  97. if( err == NO_ERROR )
  98. {
  99. //
  100. // Read the first counter DWORD.
  101. //
  102. size = sizeof(DWORD);
  103. err = RegQueryValueEx( hkey,
  104. "First Counter",
  105. NULL,
  106. &type,
  107. (LPBYTE)&dwFirstCounter,
  108. &size );
  109. if( err == NO_ERROR )
  110. {
  111. //
  112. // Read the first help DWORD.
  113. //
  114. size = sizeof(DWORD);
  115. err = RegQueryValueEx( hkey,
  116. "First Help",
  117. NULL,
  118. &type,
  119. (LPBYTE)&dwFirstHelp,
  120. &size );
  121. if ( err == NO_ERROR )
  122. {
  123. //
  124. // Update the object & counter name & help indicies.
  125. //
  126. INFODataDefinition.INFOObjectType.ObjectNameTitleIndex
  127. += dwFirstCounter;
  128. INFODataDefinition.INFOObjectType.ObjectHelpTitleIndex
  129. += dwFirstHelp;
  130. pctr = &INFODataDefinition.INFOTotalAllowedRequests;
  131. for( i = 0 ; i < NUMBER_OF_INFO_COUNTERS ; i++ )
  132. {
  133. pctr->CounterNameTitleIndex += dwFirstCounter;
  134. pctr->CounterHelpTitleIndex += dwFirstHelp;
  135. pctr++;
  136. }
  137. //
  138. // Remember that we initialized OK.
  139. //
  140. fInitOK = TRUE;
  141. //
  142. // Bump open counter.
  143. //
  144. cOpens++;
  145. // return success
  146. err = ERROR_SUCCESS;
  147. } else {
  148. // log event
  149. ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
  150. 0, IIS_INFO_UNABLE_READ_FIRST_HELP,
  151. (PSID)NULL, 0,
  152. sizeof (err), NULL,
  153. (PVOID)(&err));
  154. }
  155. } else {
  156. // log event
  157. ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
  158. 0, IIS_INFO_UNABLE_READ_FIRST_COUNTER,
  159. (PSID)NULL, 0,
  160. sizeof (err), NULL,
  161. (PVOID)(&err));
  162. }
  163. //
  164. // Close the registry if we managed to actually open it.
  165. //
  166. if( hkey != NULL )
  167. {
  168. RegCloseKey( hkey );
  169. hkey = NULL;
  170. }
  171. } else {
  172. // log event
  173. ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
  174. 0, IIS_INFO_UNABLE_OPEN_PERF_KEY,
  175. (PSID)NULL, 0,
  176. sizeof (err), NULL,
  177. (PVOID)(&err));
  178. }
  179. }
  180. return err;
  181. } // OpenINFOPerformanceData
  182. /*******************************************************************
  183. NAME: CollectINFOPerformanceData
  184. SYNOPSIS: Initializes the data structures used to communicate
  185. ENTRY: lpValueName - The name of the value to retrieve.
  186. lppData - On entry contains a pointer to the buffer to
  187. receive the completed PerfDataBlock & subordinate
  188. structures. On exit, points to the first bytes
  189. *after* the data structures added by this routine.
  190. lpcbTotalBytes - On entry contains a pointer to the
  191. size (in BYTEs) of the buffer referenced by lppData.
  192. On exit, contains the number of BYTEs added by this
  193. routine.
  194. lpNumObjectTypes - Receives the number of objects added
  195. by this routine.
  196. RETURNS: DWORD - Win32 status code. MUST be either NO_ERROR
  197. or ERROR_MORE_DATA.
  198. HISTORY:
  199. KeithMo 07-Jun-1993 Created.
  200. ********************************************************************/
  201. DWORD CollectINFOPerformanceData( LPWSTR lpValueName,
  202. LPVOID * lppData,
  203. LPDWORD lpcbTotalBytes,
  204. LPDWORD lpNumObjectTypes )
  205. {
  206. DWORD dwQueryType;
  207. ULONG cbRequired;
  208. DWORD * pdwCounter;
  209. INFO_COUNTER_BLOCK * pCounterBlock;
  210. INFO_DATA_DEFINITION * pINFODataDefinition;
  211. INET_INFO_STATISTICS_0 * pINFOStats;
  212. NET_API_STATUS neterr;
  213. //
  214. // No need to even try if we failed to open...
  215. //
  216. if( !fInitOK )
  217. {
  218. *lpcbTotalBytes = 0;
  219. *lpNumObjectTypes = 0;
  220. //
  221. // According to the Performance Counter design, this
  222. // is a successful exit. Go figure.
  223. //
  224. return NO_ERROR;
  225. }
  226. //
  227. // Determine the query type.
  228. //
  229. dwQueryType = GetQueryType( lpValueName );
  230. if (( dwQueryType == QUERY_FOREIGN ) || ( dwQueryType == QUERY_COSTLY ))
  231. {
  232. //
  233. // We don't do foreign or Costly queries.
  234. //
  235. *lpcbTotalBytes = 0;
  236. *lpNumObjectTypes = 0;
  237. return NO_ERROR;
  238. }
  239. if( dwQueryType == QUERY_ITEMS )
  240. {
  241. //
  242. // The registry is asking for a specific object. Let's
  243. // see if we're one of the chosen.
  244. //
  245. if( !IsNumberInUnicodeList(
  246. INFODataDefinition.INFOObjectType.ObjectNameTitleIndex,
  247. lpValueName ) )
  248. {
  249. *lpcbTotalBytes = 0;
  250. *lpNumObjectTypes = 0;
  251. return NO_ERROR;
  252. }
  253. }
  254. //
  255. // See if there's enough space.
  256. //
  257. pINFODataDefinition = (INFO_DATA_DEFINITION *)*lppData;
  258. //
  259. // Try to retrieve the data.
  260. //
  261. neterr = InetInfoQueryStatistics( NULL,
  262. 0,
  263. 0,
  264. (LPBYTE *)&pINFOStats );
  265. if( neterr == NERR_Success ) {
  266. cbRequired = sizeof(INFO_DATA_DEFINITION) + SIZE_OF_INFO_PERFORMANCE_DATA;
  267. if( *lpcbTotalBytes < cbRequired )
  268. {
  269. //
  270. // Nope.
  271. //
  272. *lpcbTotalBytes = 0;
  273. *lpNumObjectTypes = 0;
  274. return ERROR_MORE_DATA;
  275. }
  276. //
  277. // Copy the (constant, initialized) Object Type and counter definitions
  278. // to the caller's data buffer
  279. //
  280. memmove( pINFODataDefinition,
  281. &INFODataDefinition,
  282. sizeof(INFO_DATA_DEFINITION) );
  283. //
  284. // Format the INFO Server data.
  285. //
  286. pCounterBlock = (INFO_COUNTER_BLOCK *)( pINFODataDefinition + 1 );
  287. pCounterBlock->PerfCounterBlock.ByteLength = SIZE_OF_INFO_PERFORMANCE_DATA;
  288. //
  289. // Now move the DWORDs into the buffer.
  290. //
  291. pdwCounter = (DWORD *)(pCounterBlock + 1);
  292. //
  293. // ATQ Global counters
  294. //
  295. *pdwCounter++ = pINFOStats->AtqCtrs.TotalAllowedRequests;
  296. *pdwCounter++ = pINFOStats->AtqCtrs.TotalBlockedRequests;
  297. *pdwCounter++ = pINFOStats->AtqCtrs.TotalRejectedRequests;
  298. *pdwCounter++ = pINFOStats->AtqCtrs.CurrentBlockedRequests;
  299. *pdwCounter++ = pINFOStats->AtqCtrs.MeasuredBandwidth;
  300. //
  301. // File Handle Cache counters
  302. //
  303. *pdwCounter++ = pINFOStats->CacheCtrs.FilesCached;
  304. *pdwCounter++ = pINFOStats->CacheCtrs.TotalFilesCached;
  305. *pdwCounter++ = pINFOStats->CacheCtrs.FileHits;
  306. *pdwCounter++ = pINFOStats->CacheCtrs.FileMisses;
  307. *pdwCounter++ = pINFOStats->CacheCtrs.FileHits;
  308. *pdwCounter++ = ( pINFOStats->CacheCtrs.FileHits +
  309. pINFOStats->CacheCtrs.FileMisses);
  310. *pdwCounter++ = pINFOStats->CacheCtrs.FileFlushes;
  311. // 64BIT BUGBUG: need to change the caller to expect int64 and then
  312. // put in the whole 64 bit value here
  313. // *((DWORDLONG *)pdwCounter) =
  314. *pdwCounter++ =
  315. (DWORD)pINFOStats->CacheCtrs.CurrentFileCacheSize;
  316. // pdwCounter += sizeof(DWORDLONG) / sizeof(*pdwCounter);
  317. // *((DWORDLONG *)pdwCounter) =
  318. *pdwCounter++ =
  319. (DWORD)pINFOStats->CacheCtrs.MaximumFileCacheSize;
  320. // pdwCounter += sizeof(DWORDLONG) / sizeof(*pdwCounter);
  321. *pdwCounter++ = pINFOStats->CacheCtrs.FlushedEntries;
  322. *pdwCounter++ = pINFOStats->CacheCtrs.TotalFlushed;
  323. //
  324. // URI Cache counters
  325. //
  326. *pdwCounter++ = pINFOStats->CacheCtrs.URICached;
  327. *pdwCounter++ = pINFOStats->CacheCtrs.TotalURICached;
  328. *pdwCounter++ = pINFOStats->CacheCtrs.URIHits;
  329. *pdwCounter++ = pINFOStats->CacheCtrs.URIMisses;
  330. *pdwCounter++ = pINFOStats->CacheCtrs.URIHits;
  331. *pdwCounter++ = ( pINFOStats->CacheCtrs.URIHits +
  332. pINFOStats->CacheCtrs.URIMisses);
  333. *pdwCounter++ = pINFOStats->CacheCtrs.URIFlushes;
  334. *pdwCounter++ = pINFOStats->CacheCtrs.TotalURIFlushed;
  335. //
  336. // Blob Cache Counters
  337. //
  338. *pdwCounter++ = pINFOStats->CacheCtrs.BlobCached;
  339. *pdwCounter++ = pINFOStats->CacheCtrs.TotalBlobCached;
  340. *pdwCounter++ = pINFOStats->CacheCtrs.BlobHits;
  341. *pdwCounter++ = pINFOStats->CacheCtrs.BlobMisses;
  342. *pdwCounter++ = pINFOStats->CacheCtrs.BlobHits;
  343. *pdwCounter++ = ( pINFOStats->CacheCtrs.BlobHits +
  344. pINFOStats->CacheCtrs.BlobMisses);
  345. *pdwCounter++ = pINFOStats->CacheCtrs.BlobFlushes;
  346. *pdwCounter++ = pINFOStats->CacheCtrs.TotalBlobFlushed;
  347. //
  348. // Update arguments for return.
  349. //
  350. *lppData = (PVOID)pdwCounter;
  351. *lpNumObjectTypes = 1;
  352. *lpcbTotalBytes = DIFF((BYTE *)pdwCounter - (BYTE *)pINFODataDefinition);
  353. //
  354. // Free the API buffer.
  355. //
  356. MIDL_user_free( (LPBYTE)pINFOStats );
  357. //
  358. // Success! Honest!!
  359. //
  360. } else {
  361. //
  362. // Error retrieving statistics.
  363. //
  364. // if the server is down, we don't log an error.
  365. if ( !( neterr == RPC_S_SERVER_UNAVAILABLE ||
  366. neterr == RPC_S_UNKNOWN_IF ||
  367. neterr == ERROR_SERVICE_NOT_ACTIVE ||
  368. neterr == RPC_S_CALL_FAILED_DNE ))
  369. {
  370. // log event
  371. ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE,
  372. 0, IIS_INFO_UNABLE_QUERY_IIS_INFO_DATA,
  373. (PSID)NULL, 0,
  374. sizeof (neterr), NULL,
  375. (PVOID)(&neterr));
  376. }
  377. cbRequired = sizeof(INFO_DATA_DEFINITION) +
  378. SIZE_OF_INFO_PERFORMANCE_DATA;
  379. if( *lpcbTotalBytes < cbRequired )
  380. {
  381. //
  382. // Nope.
  383. //
  384. *lpcbTotalBytes = 0;
  385. *lpNumObjectTypes = 0;
  386. return ERROR_MORE_DATA;
  387. }
  388. // Attempt to atlest provide the definition
  389. // for the counters. This is so WMI can know
  390. // that these counters exist.
  391. memmove( pINFODataDefinition,
  392. &INFODataDefinition,
  393. sizeof(INFO_DATA_DEFINITION) );
  394. ((PERF_OBJECT_TYPE*) pINFODataDefinition)->NumInstances = PERF_NO_INSTANCES;
  395. ((PERF_OBJECT_TYPE*) pINFODataDefinition)->TotalByteLength = cbRequired;
  396. // Copy in the actual data for global
  397. memset ( (LPVOID) ( pINFODataDefinition + 1 ), 0, SIZE_OF_INFO_PERFORMANCE_DATA );
  398. // This is setting the size in the structure, it is the first
  399. // DWORD in the INFO_COUNTER_BLOCK.
  400. *((DWORD*) (pINFODataDefinition + 1)) = SIZE_OF_INFO_PERFORMANCE_DATA;
  401. *lpcbTotalBytes = cbRequired;
  402. *lpNumObjectTypes = 1;
  403. *lppData = (LPBYTE) pINFODataDefinition + cbRequired;
  404. }
  405. return NO_ERROR;
  406. } // CollectINFOPerformanceData
  407. /*******************************************************************
  408. NAME: CloseINFOPerformanceData
  409. SYNOPSIS: Terminates the performance counters.
  410. RETURNS: DWORD - Win32 status code.
  411. HISTORY:
  412. KeithMo 07-Jun-1993 Created.
  413. ********************************************************************/
  414. DWORD CloseINFOPerformanceData( VOID )
  415. {
  416. //
  417. // No real cleanup to do here.
  418. //
  419. if (--cOpens == 0) {
  420. if (hEventLog != NULL) DeregisterEventSource (hEventLog);
  421. }
  422. return NO_ERROR;
  423. } // CloseINFOPerformanceData