Source code of Windows XP (NT5)
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.

414 lines
14 KiB

  1. /****************************************************************************
  2. PROGRAM: NWPerf.c
  3. PURPOSE: Contains library routines for providing perfmon with data
  4. FUNCTIONS:
  5. *******************************************************************************/
  6. #include <nt.h>
  7. #include <ntrtl.h>
  8. #include <nturtl.h>
  9. #include <windows.h>
  10. #include <winperf.h>
  11. #include <ntddnwfs.h>
  12. #include "NWPerf.h"
  13. #include "prfutil.h"
  14. #ifndef QFE_BUILD
  15. #include "ntprfctr.h"
  16. #endif
  17. BOOL gbInitOK = FALSE;
  18. HANDLE hNetWareRdr ;
  19. extern NW_DATA_DEFINITION NWDataDefinition;
  20. #ifdef QFE_BUILD
  21. TCHAR PerformanceKeyName [] =
  22. TEXT("SYSTEM\\CurrentControlSet\\Services\\NWrdr\\Performance");
  23. TCHAR FirstCounterKeyName [] = TEXT("First Counter");
  24. TCHAR FirstHelpKeyName [] = TEXT("First Help");
  25. #endif
  26. /****************************************************************************
  27. FUNCTION: OpenNetWarePerformanceData
  28. Purpose: This routine also initializes the data structures used to pass
  29. data back to the registry
  30. Return: None.
  31. r****************************************************************************/
  32. DWORD APIENTRY
  33. OpenNetWarePerformanceData(
  34. LPWSTR pInstances )
  35. {
  36. LONG status;
  37. #ifdef QFE_BUILD
  38. HKEY hKeyPerf = 0;
  39. DWORD size;
  40. DWORD type;
  41. DWORD dwFirstCounter;
  42. DWORD dwFirstHelp;
  43. #else
  44. NT_PRODUCT_TYPE ProductType;
  45. DWORD dwFirstCounter = NWCS_CLIENT_COUNTER_INDEX ;
  46. DWORD dwFirstHelp = NWCS_CLIENT_HELP_INDEX ;
  47. #endif
  48. IO_STATUS_BLOCK IoStatusBlock;
  49. RTL_RELATIVE_NAME RelativeName;
  50. UNICODE_STRING DeviceNameU;
  51. OBJECT_ATTRIBUTES ObjectAttributes;
  52. #ifdef QFE_BUILD
  53. status = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
  54. PerformanceKeyName,
  55. 0L, KEY_ALL_ACCESS, &hKeyPerf );
  56. if (status != ERROR_SUCCESS) {
  57. goto OpenExitPoint;
  58. }
  59. size = sizeof (DWORD);
  60. status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type,
  61. (LPBYTE)&dwFirstCounter, &size);
  62. if (status != ERROR_SUCCESS) {
  63. goto OpenExitPoint;
  64. }
  65. size = sizeof (DWORD);
  66. status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName,
  67. 0L, &type, (LPBYTE)&dwFirstHelp, &size );
  68. if (status != ERROR_SUCCESS) {
  69. goto OpenExitPoint;
  70. }
  71. #endif
  72. //
  73. // NOTE: the initialization program could also retrieve
  74. // LastCounter and LastHelp if they wanted to do
  75. // bounds checking on the new number. e.g.
  76. //
  77. // counter->CounterNameTitleIndex += dwFirstCounter;
  78. // if (counter->CounterNameTitleIndex > dwLastCounter) {
  79. // LogErrorToEventLog (INDEX_OUT_OF_BOUNDS);
  80. // }
  81. NWDataDefinition.NWObjectType.ObjectNameTitleIndex += dwFirstCounter;
  82. NWDataDefinition.NWObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  83. // Counters not defined in Redirector, setup the correct IDs
  84. NWDataDefinition.PacketBurstRead.CounterNameTitleIndex += dwFirstCounter;
  85. NWDataDefinition.PacketBurstRead.CounterHelpTitleIndex += dwFirstHelp;
  86. NWDataDefinition.PacketBurstReadTimeouts.CounterNameTitleIndex += dwFirstCounter;
  87. NWDataDefinition.PacketBurstReadTimeouts.CounterHelpTitleIndex += dwFirstHelp;
  88. NWDataDefinition.PacketBurstWrite.CounterNameTitleIndex += dwFirstCounter;
  89. NWDataDefinition.PacketBurstWrite.CounterHelpTitleIndex += dwFirstHelp;
  90. NWDataDefinition.PacketBurstWriteTimeouts.CounterNameTitleIndex += dwFirstCounter;
  91. NWDataDefinition.PacketBurstWriteTimeouts.CounterHelpTitleIndex += dwFirstHelp;
  92. NWDataDefinition.PacketBurstIO.CounterNameTitleIndex += dwFirstCounter;
  93. NWDataDefinition.PacketBurstIO.CounterHelpTitleIndex += dwFirstHelp;
  94. NWDataDefinition.NetWare2XConnects.CounterNameTitleIndex += dwFirstCounter;
  95. NWDataDefinition.NetWare2XConnects.CounterHelpTitleIndex += dwFirstHelp;
  96. NWDataDefinition.NetWare3XConnects.CounterNameTitleIndex += dwFirstCounter;
  97. NWDataDefinition.NetWare3XConnects.CounterHelpTitleIndex += dwFirstHelp;
  98. NWDataDefinition.NetWare4XConnects.CounterNameTitleIndex += dwFirstCounter;
  99. NWDataDefinition.NetWare4XConnects.CounterHelpTitleIndex += dwFirstHelp;
  100. #ifndef QFE_BUILD
  101. // Check for WorkStation or Server and use the gateway indexes if
  102. // currently running on Server.
  103. // If RtlGetNtProductType is not successful or ProductType is
  104. // WinNt machine, ObjectNameTitleIndex and ObjectHelpTitleIndex are set
  105. // to the correct values already.
  106. #ifdef GATEWAY_ENABLED
  107. if ( RtlGetNtProductType( &ProductType))
  108. {
  109. if ( ProductType != NtProductWinNt )
  110. {
  111. NWDataDefinition.NWObjectType.ObjectNameTitleIndex = NWCS_GATEWAY_COUNTER_INDEX;
  112. NWDataDefinition.NWObjectType.ObjectHelpTitleIndex = NWCS_GATEWAY_HELP_INDEX;
  113. }
  114. }
  115. #endif
  116. #endif
  117. hNetWareRdr = NULL;
  118. RtlInitUnicodeString(&DeviceNameU, DD_NWFS_DEVICE_NAME_U);
  119. RelativeName.ContainingDirectory = NULL;
  120. InitializeObjectAttributes(&ObjectAttributes,
  121. &DeviceNameU,
  122. OBJ_CASE_INSENSITIVE,
  123. RelativeName.ContainingDirectory,
  124. NULL
  125. );
  126. status = NtCreateFile(&hNetWareRdr,
  127. SYNCHRONIZE,
  128. &ObjectAttributes,
  129. &IoStatusBlock,
  130. NULL,
  131. FILE_ATTRIBUTE_NORMAL,
  132. FILE_SHARE_READ | FILE_SHARE_WRITE,
  133. FILE_OPEN_IF,
  134. FILE_SYNCHRONOUS_IO_NONALERT,
  135. NULL,
  136. 0
  137. );
  138. gbInitOK = TRUE; // ok to use this function
  139. status = ERROR_SUCCESS; // for successful exit
  140. #ifdef QFE_BUILD
  141. OpenExitPoint:
  142. if (hKeyPerf)
  143. RegCloseKey (hKeyPerf); // close key to registry
  144. #endif
  145. return ((DWORD) status);
  146. }
  147. /****************************************************************************
  148. FUNCTION: CollectNetWarePerformanceData
  149. Purpose: This routine will return the data for the NetWare counters.
  150. Arguments:IN LPWSTR lpValueName
  151. pointer to a wide character string passed by registry.
  152. IN OUT LPVOID *lppData
  153. IN: pointer to the address of the buffer to receive the
  154. completed PerfDataBlock and subordinate structures. This
  155. routine will append its data to the buffer starting at
  156. the point referenced by *lppData.
  157. OUT: points to the first byte after the data structure
  158. added by this routine. This routine updated the value at
  159. lppdata after appending its data.
  160. IN OUT LPDWORD lpcbTotalBytes
  161. IN: the address of the DWORD that tells the size in bytes
  162. of the buffer referenced by the lppData argument
  163. OUT: the number of bytes added by this routine is written
  164. to the DWORD pointed to by this argument
  165. IN OUT LPDWORD NumObjectTypes
  166. IN: the address of the DWORD to receive the number of
  167. objects added by this routine
  168. OUT: the number of objects added by this routine is written
  169. to the DWORD pointed to by this argument
  170. Return: ERROR_MORE_DATA if buffer passed is too small to hold data
  171. any error conditions encountered are reported
  172. to the event log if event logging is enabled.
  173. ERROR_SUCCESS if success or any other error. Errors, however
  174. are also reported to the event log.
  175. ****************************************************************************/
  176. DWORD APIENTRY
  177. CollectNetWarePerformanceData(
  178. IN LPWSTR lpValueName,
  179. IN OUT LPVOID *lppData,
  180. IN OUT LPDWORD lpcbTotalBytes,
  181. IN OUT LPDWORD lpNumObjectTypes)
  182. {
  183. ULONG SpaceNeeded;
  184. PDWORD pdwCounter;
  185. DWORD dwQueryType;
  186. PERF_COUNTER_BLOCK *pPerfCounterBlock;
  187. NW_DATA_DEFINITION *pNWDataDefinition;
  188. LONG status;
  189. NW_REDIR_STATISTICS NWRdrStatistics;
  190. LARGE_INTEGER UNALIGNED *pliCounter;
  191. IO_STATUS_BLOCK IoStatusBlock;
  192. //
  193. // before doing anything else, see if Open went OK
  194. //
  195. if (!gbInitOK) {
  196. *lpcbTotalBytes = (DWORD) 0;
  197. *lpNumObjectTypes = (DWORD) 0;
  198. return ERROR_SUCCESS; // yes, this is a successful exit
  199. }
  200. // see if this is a foreign (i.e. non-NT) computer data request
  201. //
  202. dwQueryType = GetQueryType (lpValueName);
  203. if (dwQueryType == QUERY_FOREIGN) {
  204. // this routine does not service requests for data from
  205. // Non-NT computers
  206. *lpcbTotalBytes = (DWORD) 0;
  207. *lpNumObjectTypes = (DWORD) 0;
  208. return ERROR_SUCCESS;
  209. }
  210. // If the caller only wanted some counter, check if we have 'em
  211. if (dwQueryType == QUERY_ITEMS){
  212. if ( !(IsNumberInUnicodeList (
  213. NWDataDefinition.NWObjectType.ObjectNameTitleIndex,
  214. lpValueName))) {
  215. // request received for data object not provided by this routine
  216. *lpcbTotalBytes = (DWORD) 0;
  217. *lpNumObjectTypes = (DWORD) 0;
  218. return ERROR_SUCCESS;
  219. }
  220. }
  221. pNWDataDefinition = (NW_DATA_DEFINITION *) *lppData;
  222. SpaceNeeded = sizeof(NW_DATA_DEFINITION) + SIZE_OF_COUNTER_BLOCK;
  223. if ( *lpcbTotalBytes < SpaceNeeded ) {
  224. *lpcbTotalBytes = (DWORD) 0;
  225. *lpNumObjectTypes = (DWORD) 0;
  226. return ((DWORD) ERROR_MORE_DATA);
  227. }
  228. //
  229. // Copy the (constant, initialized) Object Type and counter definitions
  230. // to the caller's data buffer
  231. //
  232. memmove( pNWDataDefinition, &NWDataDefinition,
  233. sizeof(NW_DATA_DEFINITION) );
  234. // Point at the byte right after all the definitions
  235. pPerfCounterBlock = (PERF_COUNTER_BLOCK *) &pNWDataDefinition[1];
  236. // The first DWORD should specify the size of actual data block
  237. pPerfCounterBlock->ByteLength = SIZE_OF_COUNTER_BLOCK;
  238. // Move the pointer up
  239. pdwCounter = (PDWORD) (&pPerfCounterBlock[1]);
  240. // Open the NetWare data
  241. if ( hNetWareRdr != NULL) {
  242. status = NtFsControlFile(hNetWareRdr,
  243. NULL,
  244. NULL,
  245. NULL,
  246. &IoStatusBlock,
  247. FSCTL_NWR_GET_STATISTICS,
  248. NULL,
  249. 0,
  250. &NWRdrStatistics,
  251. sizeof(NWRdrStatistics)
  252. );
  253. }
  254. if ( hNetWareRdr != NULL && NT_SUCCESS(status) ) {
  255. pliCounter = (LARGE_INTEGER UNALIGNED * ) (&pPerfCounterBlock[1]);
  256. pliCounter->QuadPart = NWRdrStatistics.BytesReceived.QuadPart +
  257. NWRdrStatistics.BytesTransmitted.QuadPart;
  258. pdwCounter = (PDWORD) ++pliCounter;
  259. *pdwCounter = NWRdrStatistics.ReadOperations +
  260. NWRdrStatistics.WriteOperations;
  261. pliCounter = (LARGE_INTEGER UNALIGNED * ) ++pdwCounter;
  262. pliCounter->QuadPart = NWRdrStatistics.NcpsReceived.QuadPart +
  263. NWRdrStatistics.NcpsTransmitted.QuadPart;
  264. *++pliCounter = NWRdrStatistics.BytesReceived;
  265. *++pliCounter = NWRdrStatistics.NcpsReceived;
  266. *++pliCounter = NWRdrStatistics.BytesTransmitted;
  267. *++pliCounter = NWRdrStatistics.NcpsTransmitted;
  268. pdwCounter = (PDWORD) ++pliCounter;
  269. *pdwCounter = NWRdrStatistics.ReadOperations;
  270. *++pdwCounter = NWRdrStatistics.RandomReadOperations;
  271. *++pdwCounter = NWRdrStatistics.ReadNcps;
  272. *++pdwCounter = NWRdrStatistics.WriteOperations;
  273. *++pdwCounter = NWRdrStatistics.RandomWriteOperations;
  274. *++pdwCounter = NWRdrStatistics.WriteNcps;
  275. *++pdwCounter = NWRdrStatistics.Sessions;
  276. *++pdwCounter = NWRdrStatistics.Reconnects;
  277. *++pdwCounter = NWRdrStatistics.NW2xConnects;
  278. *++pdwCounter = NWRdrStatistics.NW3xConnects;
  279. *++pdwCounter = NWRdrStatistics.NW4xConnects;
  280. *++pdwCounter = NWRdrStatistics.ServerDisconnects;
  281. *++pdwCounter = NWRdrStatistics.PacketBurstReadNcps;
  282. *++pdwCounter = NWRdrStatistics.PacketBurstReadTimeouts;
  283. *++pdwCounter = NWRdrStatistics.PacketBurstWriteNcps;
  284. *++pdwCounter = NWRdrStatistics.PacketBurstWriteTimeouts;
  285. *++pdwCounter = NWRdrStatistics.PacketBurstReadNcps +
  286. NWRdrStatistics.PacketBurstWriteNcps;
  287. //
  288. // Add an extra empty DWORD to pad the buffer to an 8-byte boundary
  289. //
  290. *++pdwCounter = 0;
  291. *lppData = (LPVOID) ++pdwCounter;
  292. } else {
  293. //
  294. // Failure to access Redirector: clear counters to 0
  295. //
  296. memset(&pPerfCounterBlock[1],
  297. 0,
  298. SIZE_OF_COUNTER_BLOCK - sizeof(pPerfCounterBlock));
  299. pdwCounter = (PDWORD) ((PBYTE) pPerfCounterBlock + SIZE_OF_COUNTER_BLOCK);
  300. *lppData = (LPVOID) pdwCounter;
  301. }
  302. // We sent data for only one Object. (Remember not to confuse this
  303. // with counters. Even if more counters are added, the number of object
  304. // is still only one. However, this does not mean more objects cannot
  305. // be added
  306. *lpNumObjectTypes = 1;
  307. // Fill in the number of bytes we copied - incl. the definitions and the
  308. // counter data.
  309. *lpcbTotalBytes = (DWORD) ((PBYTE) pdwCounter - (PBYTE) pNWDataDefinition);
  310. //
  311. // Make sure the output buffer is 8-byte aligned
  312. //
  313. ASSERT((*lpcbTotalBytes & 0x7) == 0);
  314. return ERROR_SUCCESS;
  315. }
  316. /****************************************************************************
  317. FUNCTION: CloseNetWarePerformanceData
  318. Purpose: This routine closes the open handles to NetWare performance counters
  319. Return: ERROR_SUCCESS
  320. ****************************************************************************/
  321. DWORD APIENTRY
  322. CloseNetWarePerformanceData(
  323. )
  324. {
  325. if ( hNetWareRdr ) {
  326. NtClose( hNetWareRdr );
  327. hNetWareRdr = NULL;
  328. }
  329. return ERROR_SUCCESS;
  330. }