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.

800 lines
21 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. perfras.c
  5. Abstract:
  6. This file implements the Extensible Objects for the Ras object type
  7. Created:
  8. Russ Blake 24 Feb 93
  9. Thomas J. Dimitri 28 May 93
  10. Revision History
  11. Ram Cherala 15 Feb 96
  12. Don't hard code the length of the instance name in
  13. CollectRasPerformanceData.
  14. PerfMon checks the actual instance name length to determine
  15. if the name is properly formatted, so compute it for each
  16. instance name.
  17. Patrick Y. Ng 12 Aug 93
  18. --*/
  19. //
  20. // Include Files
  21. //
  22. #include <nt.h>
  23. #include <ntrtl.h>
  24. #include <nturtl.h>
  25. #include <ntddser.h>
  26. #include <windows.h>
  27. #include <string.h>
  28. #include <wcstr.h>
  29. #include <winperf.h>
  30. #include <malloc.h>
  31. #include <ntprfctr.h>
  32. #include "globals.h"
  33. #include "rasctrs.h" // error message definition
  34. #include "perfmsg.h"
  35. #include "perfutil.h"
  36. #include "dataras.h"
  37. #include "port.h"
  38. #include <rasman.h>
  39. #include <serial.h>
  40. #include <isdn.h>
  41. #include <raserror.h>
  42. #include <stdarg.h>
  43. #include <string.h>
  44. #include <stdio.h>
  45. //
  46. // References to constants which initialize the Object type definitions
  47. //
  48. DWORD dwOpenCount = 0; // count of "Open" threads
  49. BOOL bInitOK = FALSE; // true = DLL initialized OK
  50. CRITICAL_SECTION g_csPerf;
  51. //
  52. // Function Prototypes
  53. //
  54. // these are used to insure that the data collection functions
  55. // accessed by Perflib will have the correct calling format.
  56. //
  57. PM_OPEN_PROC OpenRasPerformanceData;
  58. PM_COLLECT_PROC CollectRasPerformanceData;
  59. PM_CLOSE_PROC CloseRasPerformanceData;
  60. BOOL
  61. FRasmanStarted()
  62. {
  63. SC_HANDLE schandle = NULL;
  64. SC_HANDLE svchandle = NULL;
  65. BOOL fRet = FALSE;
  66. //
  67. // Check to see if rasman service is started.
  68. // fail if it isn't - we don't want ras perf
  69. // to start rasman service.
  70. //
  71. schandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  72. if(NULL != schandle)
  73. {
  74. svchandle = OpenService(schandle,
  75. "RASMAN",
  76. SERVICE_QUERY_STATUS);
  77. if(NULL != svchandle)
  78. {
  79. SERVICE_STATUS status;
  80. if( (QueryServiceStatus(svchandle, &status))
  81. && (status.dwCurrentState == SERVICE_RUNNING))
  82. {
  83. fRet = TRUE;
  84. }
  85. CloseServiceHandle(svchandle);
  86. }
  87. CloseServiceHandle(schandle);
  88. }
  89. return fRet;
  90. }
  91. DWORD
  92. DwInitializeRasCounters()
  93. {
  94. LONG status;
  95. HKEY hKeyDriverPerf = NULL;
  96. DWORD size;
  97. DWORD type;
  98. DWORD dwFirstCounter;
  99. DWORD dwFirstHelp;
  100. if (!dwOpenCount)
  101. {
  102. InitializeCriticalSection(&g_csPerf);
  103. //
  104. // open Eventlog interface
  105. //
  106. hEventLog = MonOpenEventLog();
  107. //
  108. // Load rasman.dll and get all the required functions.
  109. //
  110. status = InitRasFunctions();
  111. if( status != ERROR_SUCCESS )
  112. {
  113. REPORT_ERROR (RASPERF_UNABLE_DO_IOCTL, LOG_USER);
  114. // this is fatal, if we can't get data then there's no
  115. // point in continuing.
  116. goto OpenExitPoint;
  117. }
  118. // AnshulD: BUG: 750860
  119. // get counter and help index base values
  120. // update static data structures by adding base to
  121. // offset value in structure.
  122. status = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
  123. TEXT("SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Performance"),
  124. 0L,
  125. KEY_READ,
  126. &hKeyDriverPerf);
  127. if (status != ERROR_SUCCESS)
  128. {
  129. REPORT_ERROR (RASPERF_UNABLE_OPEN_DRIVER_KEY, LOG_USER);
  130. // this is fatal, if we can't get the base values of the
  131. // counter or help names, then the names won't be available
  132. // to the requesting application so there's not much
  133. // point in continuing.
  134. goto OpenExitPoint;
  135. }
  136. size = sizeof (DWORD);
  137. status = RegQueryValueEx( hKeyDriverPerf,
  138. TEXT("First Counter"),
  139. 0L,
  140. &type,
  141. (LPBYTE)&dwFirstCounter,
  142. &size);
  143. if (status != ERROR_SUCCESS)
  144. {
  145. // this is fatal, if we can't get the base values of the
  146. // counter or help names, then the names won't be available
  147. // to the requesting application so there's not much
  148. // point in continuing.
  149. REPORT_ERROR (RASPERF_UNABLE_READ_FIRST_COUNTER, LOG_USER);
  150. goto OpenExitPoint;
  151. }
  152. size = sizeof (DWORD);
  153. status = RegQueryValueEx( hKeyDriverPerf,
  154. TEXT("First Help"),
  155. 0L,
  156. &type,
  157. (LPBYTE)&dwFirstHelp,
  158. &size);
  159. if (status != ERROR_SUCCESS)
  160. {
  161. // this is fatal, if we can't get the base values of the
  162. // counter or help names, then the names won't be available
  163. // to the requesting application so there's not much
  164. // point in continuing.
  165. REPORT_ERROR (RASPERF_UNABLE_READ_FIRST_HELP, LOG_USER);
  166. goto OpenExitPoint;
  167. }
  168. InitObjectCounterIndex( dwFirstCounter,
  169. dwFirstHelp );
  170. bInitOK = TRUE; // ok to use this function
  171. }
  172. dwOpenCount++; // increment OPEN counter
  173. status = ERROR_SUCCESS; // for successful exit
  174. OpenExitPoint:
  175. if ( hKeyDriverPerf )
  176. RegCloseKey (hKeyDriverPerf);
  177. return status;
  178. }
  179. //***
  180. //
  181. // Routine Description:
  182. //
  183. // This routine will open and map the memory used by the RAS driver to
  184. // pass performance data in. This routine also initializes the data
  185. // structures used to pass data back to the registry
  186. //
  187. // Arguments:
  188. //
  189. // Pointer to object ID of each device to be opened (RAS)
  190. //
  191. //
  192. // Return Value:
  193. //
  194. // None.
  195. //
  196. //***
  197. DWORD OpenRasPerformanceData( LPWSTR lpDeviceNames )
  198. {
  199. LONG status;
  200. //
  201. // Since SCREG is multi-threaded and will call this routine in
  202. // order to service remote performance queries, this library
  203. // must keep track of how many times it has been opened (i.e.
  204. // how many threads have accessed it). the registry routines will
  205. // limit access to the initialization routine to only one thread
  206. // at a time so synchronization (i.e. reentrancy) should not be
  207. // a problem
  208. //
  209. status = DwInitializeRasCounters();
  210. return status;
  211. }
  212. //***
  213. //
  214. // Routine Description:
  215. //
  216. // This routine will return the data for the RAS counters.
  217. //
  218. // Arguments:
  219. //
  220. // IN OUT LPWSTR lpValueName
  221. // pointer to a wide character string passed by registry.
  222. //
  223. // IN OUT LPVOID *lppData
  224. // IN: pointer to the address of the buffer to receive the completed
  225. // PerfDataBlock and subordinate structures. This routine will
  226. // append its data to the buffer starting at the point referenced
  227. // by *lppData.
  228. // OUT: points to the first byte after the data structure added by this
  229. // routine. This routine updated the value at lppdata after appending
  230. // its data.
  231. //
  232. // IN OUT LPDWORD lpcbTotalBytes
  233. // IN: the address of the DWORD that tells the size in bytes of the
  234. // buffer referenced by the lppData argument
  235. // OUT: the number of bytes added by this routine is written to the
  236. // DWORD pointed to by this argument
  237. //
  238. // IN OUT LPDWORD NumObjectTypes
  239. // IN: the address of the DWORD to receive the number of objects added
  240. // by this routine
  241. // OUT: the number of objects added by this routine is written to the
  242. // DWORD pointed to by this argument
  243. //
  244. // Return Value:
  245. //
  246. // ERROR_MORE_DATA if buffer passed is too small to hold data
  247. // any error conditions encountered are reported to the event log if
  248. // event logging is enabled.
  249. //
  250. // ERROR_SUCCESS if success or any other error. Errors, however are
  251. // also reported to the event log.
  252. //
  253. //***
  254. DWORD CollectRasPerformanceData(
  255. IN LPWSTR lpValueName,
  256. IN OUT LPVOID *lppData,
  257. IN OUT LPDWORD lpcbTotalBytes,
  258. IN OUT LPDWORD lpNumObjectTypes )
  259. {
  260. // Variables for reformating the data
  261. NTSTATUS Status;
  262. ULONG SpaceNeeded;
  263. PBYTE pbIn = (PBYTE) *lppData;
  264. // variables used for error logging
  265. DWORD dwQueryType;
  266. // Variables used to record which objects are required
  267. static BOOL IsRasPortObject;
  268. static BOOL IsRasTotalObject;
  269. if ( lpValueName == NULL ||
  270. lppData == NULL || *lppData == NULL ||
  271. lpcbTotalBytes == NULL || lpNumObjectTypes == NULL ) {
  272. if ( lpcbTotalBytes ) *lpcbTotalBytes = 0;
  273. if ( lpNumObjectTypes ) *lpNumObjectTypes = 0;
  274. return ERROR_SUCCESS;
  275. }
  276. if(!bInitOK)
  277. {
  278. Status = DwInitializeRasCounters();
  279. }
  280. //
  281. // before doing anything else, see if Open went OK
  282. //
  283. if (!bInitOK)
  284. {
  285. // unable to continue because open failed.
  286. *lpcbTotalBytes = (DWORD) 0;
  287. *lpNumObjectTypes = (DWORD) 0;
  288. return ERROR_SUCCESS; // yes, this is a successful exit
  289. }
  290. if(!FRasmanStarted())
  291. {
  292. PRAS_PORT_DATA_DEFINITION pRasPortDataDefinition;
  293. PRAS_TOTAL_DATA_DEFINITION pRasTotalDataDefinition;
  294. PPERF_COUNTER_BLOCK pPerfCounterBlock;
  295. PVOID pData;
  296. DWORD TotalBytes = 0;
  297. DWORD ObjectTypes = 0;
  298. DWORD BytesRequired;
  299. BytesRequired = ALIGN8(sizeof(RAS_PORT_DATA_DEFINITION)) +
  300. ALIGN8(sizeof(RAS_TOTAL_DATA_DEFINITION))+
  301. ALIGN8(SIZE_OF_RAS_TOTAL_PERFORMANCE_DATA);
  302. if ( *lpcbTotalBytes < BytesRequired ) {
  303. *lpcbTotalBytes = 0;
  304. *lpNumObjectTypes = 0;
  305. return ERROR_MORE_DATA;
  306. }
  307. pData = *lppData;
  308. //
  309. // Copy the (constant, initialized) RAS PORT Object Type and
  310. // counter definitions to the caller's data buffer
  311. //
  312. pRasPortDataDefinition = pData;
  313. memcpy( pRasPortDataDefinition,
  314. &gRasPortDataDefinition,
  315. sizeof(RAS_PORT_DATA_DEFINITION));
  316. //
  317. // Move pData to the location where we are going to copy the
  318. // RAS_TOTAL_DATA_DEFINITION
  319. //
  320. pData = (PBYTE) pData + ALIGN8(sizeof(RAS_PORT_DATA_DEFINITION));
  321. TotalBytes += ALIGN8(sizeof(RAS_PORT_DATA_DEFINITION));
  322. pRasPortDataDefinition->RasObjectType.TotalByteLength =
  323. ALIGN8(sizeof(RAS_PORT_DATA_DEFINITION));
  324. ObjectTypes++;
  325. //
  326. // Copy the (constant, initialized) RAS TOTAL Object Type and
  327. // counter definitions to the caller's data buffer
  328. //
  329. memcpy( pData,
  330. &gRasTotalDataDefinition,
  331. sizeof(RAS_TOTAL_DATA_DEFINITION));
  332. //
  333. // Move pData to the location where we are going to copy the
  334. // counter block for RAS TOTAL
  335. //
  336. pData = (PBYTE) pData + ALIGN8(sizeof(RAS_TOTAL_DATA_DEFINITION));
  337. TotalBytes += ALIGN8(sizeof(RAS_TOTAL_DATA_DEFINITION));
  338. //
  339. // Set all the counter values to 0
  340. //
  341. memset ( pData, 0, ALIGN8(SIZE_OF_RAS_TOTAL_PERFORMANCE_DATA));
  342. //
  343. // Set the Bytelength field of the counter block
  344. //
  345. pPerfCounterBlock = pData;
  346. pPerfCounterBlock->ByteLength = ALIGN8(SIZE_OF_RAS_TOTAL_PERFORMANCE_DATA);
  347. //
  348. // Move pData to the end of the RAS TOTAL counter block
  349. //
  350. pData = (PBYTE) pData + ALIGN8(SIZE_OF_RAS_TOTAL_PERFORMANCE_DATA);
  351. TotalBytes += ALIGN8(SIZE_OF_RAS_TOTAL_PERFORMANCE_DATA);
  352. ObjectTypes++;
  353. *lpcbTotalBytes = TotalBytes;
  354. *lpNumObjectTypes = ObjectTypes;
  355. *lppData = pData;
  356. return ERROR_SUCCESS;
  357. }
  358. //
  359. // Rasman is up and running.
  360. //
  361. //
  362. // Reset some output variables.
  363. //
  364. *lpNumObjectTypes = 0;
  365. EnterCriticalSection(&g_csPerf);
  366. //
  367. // Initialize all the port information.
  368. //
  369. if(ERROR_SUCCESS != InitPortInfo())
  370. {
  371. REPORT_ERROR_DATA (RASPERF_UNABLE_CREATE_PORT_TABLE, LOG_USER,
  372. &status, sizeof(status));
  373. // this is fatal, if we can't get the base values of the
  374. // counter or help names, then the names won't be available
  375. // to the requesting application so there's not much
  376. // point in continuing.
  377. *lpcbTotalBytes = (DWORD) 0;
  378. *lpNumObjectTypes = (DWORD) 0;
  379. LeaveCriticalSection(&g_csPerf);
  380. return ERROR_SUCCESS;
  381. }
  382. //
  383. // see if this is a foreign (i.e. non-NT) computer data request
  384. //
  385. dwQueryType = GetQueryType (lpValueName);
  386. if (dwQueryType == QUERY_FOREIGN)
  387. {
  388. // this routine does not service requests for data from
  389. // Non-NT computers
  390. *lpcbTotalBytes = (DWORD) 0;
  391. *lpNumObjectTypes = (DWORD) 0;
  392. LeaveCriticalSection(&g_csPerf);
  393. return ERROR_SUCCESS;
  394. }
  395. else if (dwQueryType == QUERY_ITEMS)
  396. {
  397. IsRasPortObject = IsNumberInUnicodeList (gRasPortDataDefinition.RasObjectType.ObjectNameTitleIndex,
  398. lpValueName);
  399. IsRasTotalObject = IsNumberInUnicodeList (gRasTotalDataDefinition.RasObjectType.ObjectNameTitleIndex,
  400. lpValueName);
  401. if ( !IsRasPortObject && !IsRasTotalObject )
  402. {
  403. //
  404. // request received for data object not provided by this routine
  405. //
  406. *lpcbTotalBytes = (DWORD) 0;
  407. *lpNumObjectTypes = (DWORD) 0;
  408. LeaveCriticalSection(&g_csPerf);
  409. return ERROR_SUCCESS;
  410. }
  411. }
  412. else if( dwQueryType == QUERY_GLOBAL )
  413. {
  414. IsRasPortObject = IsRasTotalObject = TRUE;
  415. }
  416. //
  417. // Now check to see if we have enough space to hold all the data
  418. //
  419. SpaceNeeded = GetSpaceNeeded(IsRasPortObject, IsRasTotalObject);
  420. if ( *lpcbTotalBytes < SpaceNeeded )
  421. {
  422. *lpcbTotalBytes = (DWORD) 0;
  423. *lpNumObjectTypes = (DWORD) 0;
  424. LeaveCriticalSection(&g_csPerf);
  425. return ERROR_MORE_DATA;
  426. }
  427. //
  428. // Collect all the RAS statistics now.
  429. //
  430. Status = CollectRasStatistics();
  431. if( Status != ERROR_SUCCESS )
  432. {
  433. REPORT_ERROR_DATA (RASPERF_CANNOT_GET_RAS_STATISTICS, LOG_USER,
  434. &Status, sizeof(Status));
  435. *lpcbTotalBytes = (DWORD) 0;
  436. *lpNumObjectTypes = (DWORD) 0;
  437. LeaveCriticalSection(&g_csPerf);
  438. return ERROR_SUCCESS;
  439. }
  440. //
  441. // We first fill in the data for object Ras Port, if needed.
  442. //
  443. if( IsRasPortObject )
  444. {
  445. PRAS_PORT_DATA_DEFINITION pRasPortDataDefinition;
  446. RAS_PORT_INSTANCE_DEFINITION RasPortInstanceDefinition;
  447. PRAS_PORT_INSTANCE_DEFINITION pRasPortInstanceDefinition;
  448. DWORD cPorts;
  449. DWORD i;
  450. PVOID pData;
  451. cPorts = GetNumOfPorts();
  452. pRasPortDataDefinition = (PRAS_PORT_DATA_DEFINITION) *lppData;
  453. //
  454. // Copy the (constant, initialized) Object Type and counter definitions
  455. // to the caller's data buffer
  456. //
  457. memcpy( pRasPortDataDefinition,
  458. &gRasPortDataDefinition,
  459. sizeof(RAS_PORT_DATA_DEFINITION));
  460. //
  461. // Now copy the instance definition and counter block.
  462. //
  463. //
  464. // First construct the default perf instance definition.
  465. //
  466. RasPortInstanceDefinition.RasInstanceType.ByteLength =
  467. ALIGN8(sizeof(RAS_PORT_INSTANCE_DEFINITION));
  468. RasPortInstanceDefinition.RasInstanceType.ParentObjectTitleIndex = 0;
  469. RasPortInstanceDefinition.RasInstanceType.ParentObjectInstance = 0;
  470. RasPortInstanceDefinition.RasInstanceType.NameOffset =
  471. sizeof(PERF_INSTANCE_DEFINITION);
  472. //DbgPrint("RASCTRS: RasPortinstanceDefinition.ByteLength = 0x%x\n",
  473. // RasPortInstanceDefinition.RasInstanceType.ByteLength);
  474. /* Don't hard code the length of the instance name.
  475. ** PerfMon checks the actual instance name length to determine
  476. ** if the name is properly formatted, so compute it for
  477. ** each instance name. ramc 2/15/96.
  478. ** RasPortInstanceDefinition.RasInstanceType.NameLength =
  479. ** sizeof( WCHAR ) * MAX_PORT_NAME;
  480. */
  481. //
  482. // Get to the end of the data definition.
  483. //
  484. // pData = (PVOID) &(pRasPortDataDefinition[1]);
  485. pData = ((PBYTE) pRasPortDataDefinition + ALIGN8(sizeof(RAS_PORT_DATA_DEFINITION)));
  486. for( i=0; i < cPorts; i++ )
  487. {
  488. //DbgPrint("RASCTRS: port %d, pData = 0x%x\n", i, pData);
  489. //
  490. // First copy the instance definition data.
  491. //
  492. RasPortInstanceDefinition.RasInstanceType.UniqueID = PERF_NO_UNIQUE_ID;
  493. lstrcpyW( (LPWSTR)&RasPortInstanceDefinition.InstanceName,
  494. GetInstanceName(i) );
  495. // Compute the instance name length
  496. RasPortInstanceDefinition.RasInstanceType.NameLength =
  497. (lstrlenW(RasPortInstanceDefinition.InstanceName) + 1) *
  498. sizeof( WCHAR );
  499. memcpy( pData, &RasPortInstanceDefinition,
  500. sizeof( RasPortInstanceDefinition ) );
  501. //
  502. // Move pPerfInstanceDefinition to the beginning of data block.
  503. //
  504. pData = (PVOID)((PBYTE) pData + ALIGN8(sizeof(RAS_PORT_INSTANCE_DEFINITION)));
  505. //
  506. // Get the data block. Note that pPerfInstanceDefinition will be
  507. // set to the next available byte.
  508. //
  509. GetInstanceData( i, &pData );
  510. }
  511. //
  512. // Set *lppData to the next available byte.
  513. //
  514. *lppData = pData;
  515. (*lpNumObjectTypes)++;
  516. }
  517. //
  518. // Then we fill in the data for object Ras Total, if needed.
  519. //
  520. if( IsRasTotalObject )
  521. {
  522. PRAS_TOTAL_DATA_DEFINITION pRasTotalDataDefinition;
  523. PVOID pData;
  524. pRasTotalDataDefinition = (PRAS_TOTAL_DATA_DEFINITION) *lppData;
  525. //DbgPrint("RASCTRS: RasTotalDataDefinition = 0x%x\n",
  526. // pRasTotalDataDefinition);
  527. //
  528. // Copy the (constant, initialized) Object Type and counter definitions
  529. // to the caller's data buffer
  530. //
  531. memcpy( pRasTotalDataDefinition,
  532. &gRasTotalDataDefinition,
  533. sizeof(RAS_TOTAL_DATA_DEFINITION));
  534. //
  535. // Now copy the counter block.
  536. //
  537. //
  538. // Set pRasTotalDataDefinition to the beginning of counter block.
  539. //
  540. // pData = (PVOID) &(pRasTotalDataDefinition[1]);
  541. pData = (PBYTE) pRasTotalDataDefinition + ALIGN8(sizeof(RAS_TOTAL_DATA_DEFINITION));
  542. //DbgPrint("RASCTRS: pData for total = 0x%x\n", pData);
  543. GetTotalData( &pData );
  544. //
  545. // Set *lppData to the next available byte.
  546. //
  547. *lppData = pData;
  548. (*lpNumObjectTypes)++;
  549. }
  550. //DbgPrint("RASCTRS: pbOut = 0x%x\n", *lppData);
  551. *lpcbTotalBytes = SpaceNeeded;
  552. /*
  553. DbgPrint("pbIn+SpaceNeeded=0x%x, *lppData=0x%x\n",
  554. pbIn+SpaceNeeded,
  555. *lppData);
  556. */
  557. ASSERT((pbIn + SpaceNeeded) == (PBYTE) *lppData);
  558. LeaveCriticalSection(&g_csPerf);
  559. return ERROR_SUCCESS;
  560. }
  561. //***
  562. //
  563. // Routine Description:
  564. //
  565. // This routine closes the open handles to RAS device performance
  566. // counters.
  567. //
  568. // Arguments:
  569. //
  570. // None.
  571. //
  572. // Return Value:
  573. //
  574. // ERROR_SUCCESS
  575. //
  576. //***
  577. DWORD CloseRasPerformanceData()
  578. {
  579. if(!bInitOK)
  580. {
  581. return ERROR_SUCCESS;
  582. }
  583. if (!(--dwOpenCount))
  584. {
  585. // when this is the last thread...
  586. MonCloseEventLog();
  587. EnterCriticalSection(&g_csPerf);
  588. ClosePortInfo();
  589. DeleteCriticalSection(&g_csPerf);
  590. }
  591. return ERROR_SUCCESS;
  592. }