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.

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