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.

564 lines
15 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. perfdhcp.c
  7. This file implements the Extensible Performance Objects for
  8. the DHCP Server service.
  9. FILE HISTORY:
  10. KeithMo 07-Jun-1993 Created, based on RussBl's sample code.
  11. RameshV 05-Aug-1998 Adapted to DHCP Server service.
  12. Used Shared memory instead of LPC
  13. */
  14. #define UNICODE 1
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <winperf.h>
  20. #include <lm.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <assert.h>
  24. #include "dhcpctrs.h"
  25. #include "perfmsg.h"
  26. #include "perfutil.h"
  27. #include "datadhcp.h"
  28. #include "perfctr.h"
  29. #pragma warning (disable : 4201)
  30. #include <dhcpapi.h>
  31. #pragma warning (default : 4201)
  32. //
  33. // Private globals.
  34. //
  35. LONG cOpens = 0; // Active "opens" reference count.
  36. BOOL fInitOK = FALSE; // TRUE if DLL initialized OK.
  37. BOOL sfLogOpen = FALSE; //indicates whether the log is
  38. //open or closed
  39. BOOL sfErrReported = FALSE; //to prevent the same error from being
  40. //logged continuously
  41. #define LOCAL_SERVER TEXT("127.0.0.1")
  42. //
  43. // Public prototypes.
  44. //
  45. PM_OPEN_PROC OpenDhcpPerformanceData;
  46. PM_COLLECT_PROC CollectDhcpPerformanceData;
  47. PM_CLOSE_PROC CloseDhcpPerformanceData;
  48. //
  49. // Private helper functions
  50. //
  51. LPDHCP_PERF_STATS SharedMem;
  52. HANDLE ShSegment = NULL;
  53. BOOL fSharedMemInitialized = FALSE;
  54. DWORD
  55. InitSharedMem(
  56. VOID
  57. )
  58. {
  59. ULONG Error = ERROR_SUCCESS;
  60. if( FALSE == fSharedMemInitialized ) {
  61. // create named temporary mapping file
  62. SharedMem = NULL;
  63. ShSegment = CreateFileMapping(
  64. INVALID_HANDLE_VALUE,
  65. NULL,
  66. PAGE_READWRITE,
  67. 0,
  68. sizeof(DHCP_PERF_STATS),
  69. (LPCWSTR)DHCPCTR_SHARED_MEM_NAME
  70. );
  71. if( NULL != ShSegment ) {
  72. // we have a file now map a view into it
  73. SharedMem = (LPVOID) MapViewOfFile(
  74. ShSegment,
  75. FILE_MAP_READ,
  76. 0,
  77. 0,
  78. sizeof(DHCP_PERF_STATS)
  79. );
  80. if( NULL != SharedMem ) {
  81. fSharedMemInitialized = TRUE;
  82. } else {
  83. // unable to map view
  84. Error = GetLastError();
  85. CloseHandle(ShSegment);
  86. ShSegment = NULL;
  87. // SharedMem is NULL;
  88. }
  89. } else {
  90. // unable to create file mapping
  91. Error = GetLastError();
  92. // ShSegment is NULL;
  93. // SharedMem is NULL;
  94. }
  95. } else {
  96. // already initialized so continue
  97. }
  98. return Error;
  99. }
  100. VOID
  101. CleanupSharedMem(
  102. VOID
  103. )
  104. {
  105. if( FALSE == fSharedMemInitialized ) return;
  106. if( NULL != SharedMem ) UnmapViewOfFile( SharedMem );
  107. if( NULL != ShSegment ) CloseHandle( ShSegment );
  108. SharedMem = NULL;
  109. ShSegment = NULL;
  110. fSharedMemInitialized = FALSE;
  111. }
  112. //
  113. // Public functions.
  114. //
  115. /*******************************************************************
  116. NAME: OpenDhcpPPerformanceData
  117. SYNOPSIS: Initializes the data structures used to communicate
  118. performance counters with the registry.
  119. ENTRY: lpDeviceNames - Poitner to object ID of each device
  120. to be opened.
  121. RETURNS: DWORD - Win32 status code.
  122. HISTORY:
  123. Pradeepb 20-July-1993 Created.`
  124. RameshV 05-Aug-1998 Adapted for DHCP.
  125. ********************************************************************/
  126. DWORD OpenDhcpPerformanceData( LPWSTR lpDeviceNames )
  127. {
  128. DWORD err = NO_ERROR;
  129. DWORD dwFirstCounter = 0;
  130. DWORD dwFirstHelp = 0;
  131. //
  132. // Since SCREG is multi-threaded and will call this routine in
  133. // order to service remote performance queries, this library
  134. // must keep track of how many times it has been opened (i.e.
  135. // how many threads have accessed it). The registry routines will
  136. // limit access to the initialization routine to only one thread
  137. // at a time so synchronization (i.e. reentrancy) should not be
  138. // a problem.
  139. //
  140. UNREFERENCED_PARAMETER (lpDeviceNames);
  141. if( !fInitOK )
  142. {
  143. PERF_COUNTER_DEFINITION * pctr;
  144. DWORD i;
  145. HKEY DhcpKey;
  146. REPORT_INFORMATION( DHCP_OPEN_ENTERED, LOG_VERBOSE );
  147. //
  148. // This is the *first* open.
  149. //
  150. err = RegOpenKeyExW(
  151. HKEY_LOCAL_MACHINE,
  152. (LPCWSTR)L"System\\CurrentControlSet\\Services\\DHCPServer\\Performance",
  153. 0,
  154. KEY_READ,
  155. &DhcpKey
  156. );
  157. if( ERROR_SUCCESS == err ) {
  158. ULONG dwSize = sizeof(dwFirstCounter);
  159. err = RegQueryValueExW(
  160. DhcpKey,
  161. (LPCWSTR)L"First Counter",
  162. NULL,
  163. NULL,
  164. (LPBYTE)&dwFirstCounter,
  165. &dwSize
  166. );
  167. RegCloseKey(DhcpKey);
  168. }
  169. if (err == ERROR_SUCCESS) {
  170. // first help index is 1 more than first counter index as LODCTR installs it.
  171. dwFirstHelp = dwFirstCounter + 1;
  172. err = InitSharedMem();
  173. if( ERROR_SUCCESS != err ) return err;
  174. if (!MonOpenEventLog(APP_NAME))
  175. {
  176. sfLogOpen = TRUE;
  177. }
  178. if( ERROR_SUCCESS == err ) {
  179. //
  180. // Update the object & counter name & help indicies.
  181. //
  182. DhcpDataDataDefinition.ObjectType.ObjectNameTitleIndex
  183. += dwFirstCounter;
  184. DhcpDataDataDefinition.ObjectType.ObjectHelpTitleIndex
  185. += dwFirstHelp;
  186. pctr = &DhcpDataDataDefinition.PacketsReceived;
  187. for( i = 0 ; i < NUMBER_OF_DHCPDATA_COUNTERS ; i++ )
  188. {
  189. pctr->CounterNameTitleIndex += dwFirstCounter;
  190. pctr->CounterHelpTitleIndex += dwFirstHelp;
  191. pctr++;
  192. }
  193. //
  194. // Remember that we initialized OK.
  195. //
  196. fInitOK = TRUE;
  197. }
  198. } else {
  199. // if here, then either the perf key or the counter strings
  200. // have not been installed so set the error code.
  201. err = DHCP_NOT_INSTALLED;
  202. REPORT_WARNING( DHCP_NOT_INSTALLED, LOG_DEBUG );
  203. }
  204. }
  205. //
  206. // Bump open counter.
  207. //
  208. if( err == NO_ERROR )
  209. {
  210. InterlockedIncrement(&cOpens);
  211. }
  212. //
  213. // if sfLogOpen is FALSE, it means that all threads we closed the
  214. // event log in CloseDHCPPerformanceData
  215. //
  216. if (!sfLogOpen)
  217. {
  218. MonOpenEventLog(APP_NAME);
  219. }
  220. if( 0 == err ) {
  221. REPORT_INFORMATION( DHCP_OPEN_SUCCESS, LOG_DEBUG );
  222. } else {
  223. REPORT_INFORMATION( DHCP_OPEN_FAILURE, LOG_DEBUG );
  224. }
  225. if (DHCP_NOT_INSTALLED == err) {
  226. // sanitize the return value to avoid spamming the event log
  227. err = ERROR_SUCCESS;
  228. // this will prevent perflib from generating an error and
  229. // since the fInitOK flag is still FLASE, all calls to the collect
  230. // function will return no data.
  231. // however, the DLL will still be loaded and the functions called
  232. // even though there's no real point.
  233. // returning an error code, however will spam the event log with
  234. // error messages so this is the quitest way to go.
  235. }
  236. return err;
  237. } // OpenDHCPPerformanceData
  238. /*******************************************************************
  239. NAME: CollectDhcpPerformanceData
  240. SYNOPSIS: Initializes the data structures used to communicate
  241. ENTRY: lpValueName - The name of the value to retrieve.
  242. lppData - On entry contains a pointer to the buffer to
  243. receive the completed PerfDataBlock & subordinate
  244. structures. On exit, points to the first bytes
  245. *after* the data structures added by this routine.
  246. lpcbTotalBytes - On entry contains a pointer to the
  247. size (in BYTEs) of the buffer referenced by lppData.
  248. On exit, contains the number of BYTEs added by this
  249. routine.
  250. lpNumObjectTypes - Receives the number of objects added
  251. by this routine.
  252. RETURNS: DWORD - Win32 status code. MUST be either NO_ERROR
  253. or ERROR_MORE_DATA.
  254. HISTORY:
  255. KeithMo 07-Jun-1993 Created.
  256. ********************************************************************/
  257. DWORD CollectDhcpPerformanceData( LPWSTR lpValueName,
  258. LPVOID * lppData,
  259. LPDWORD lpcbTotalBytes,
  260. LPDWORD lpNumObjectTypes )
  261. {
  262. DWORD dwQueryType;
  263. ULONG cbRequired;
  264. DWORD *pdwCounter;
  265. DHCPDATA_COUNTER_BLOCK *pCounterBlock;
  266. DHCPDATA_DATA_DEFINITION *pDhcpDataDataDefinition;
  267. DWORD Status;
  268. DHCP_PERF_STATS PerfStats;
  269. //
  270. // No need to even try if we failed to open...
  271. //
  272. if( NULL == lpValueName ) {
  273. REPORT_INFORMATION( DHCP_COLLECT_ENTERED, LOG_VERBOSE );
  274. } else {
  275. REPORT_INFORMATION_DATA(
  276. DHCP_COLLECT_ENTERED, LOG_VERBOSE,
  277. (LPVOID) lpValueName, (DWORD)(wcslen(lpValueName)*sizeof(WCHAR))
  278. );
  279. }
  280. if( !fInitOK )
  281. {
  282. *lpcbTotalBytes = 0;
  283. *lpNumObjectTypes = 0;
  284. //
  285. // According to the Performance Counter design, this
  286. // is a successful exit. Go figure.
  287. //
  288. return NO_ERROR;
  289. }
  290. //
  291. // Determine the query type.
  292. //
  293. dwQueryType = GetQueryType( lpValueName );
  294. if( dwQueryType == QUERY_FOREIGN )
  295. {
  296. //
  297. // We don't do foreign queries.
  298. //
  299. *lpcbTotalBytes = 0;
  300. *lpNumObjectTypes = 0;
  301. return NO_ERROR;
  302. }
  303. if( dwQueryType == QUERY_ITEMS )
  304. {
  305. //
  306. // The registry is asking for a specific object. Let's
  307. // see if we're one of the chosen.
  308. //
  309. if( !IsNumberInUnicodeList(
  310. DhcpDataDataDefinition.ObjectType.ObjectNameTitleIndex,
  311. lpValueName ) )
  312. {
  313. *lpcbTotalBytes = 0;
  314. *lpNumObjectTypes = 0;
  315. return NO_ERROR;
  316. }
  317. }
  318. //
  319. // See if there's enough space.
  320. //
  321. pDhcpDataDataDefinition = (DHCPDATA_DATA_DEFINITION *)*lppData;
  322. cbRequired = sizeof(DHCPDATA_DATA_DEFINITION) +
  323. DHCPDATA_SIZE_OF_PERFORMANCE_DATA;
  324. if( *lpcbTotalBytes < cbRequired )
  325. {
  326. DWORD Diff = (cbRequired - *lpcbTotalBytes );
  327. //
  328. // Nope.
  329. //
  330. *lpcbTotalBytes = 0;
  331. *lpNumObjectTypes = 0;
  332. REPORT_INFORMATION_DATA(
  333. DHCP_COLLECT_NO_MEM, LOG_VERBOSE,
  334. (PVOID) &Diff, sizeof(Diff) );
  335. return ERROR_MORE_DATA;
  336. }
  337. //
  338. // Copy the (constant, initialized) Object Type and counter definitions
  339. // to the caller's data buffer
  340. //
  341. memmove( pDhcpDataDataDefinition,
  342. &DhcpDataDataDefinition,
  343. sizeof(DHCPDATA_DATA_DEFINITION) );
  344. //
  345. // Try to retrieve the data.
  346. //
  347. if( NULL == SharedMem ) {
  348. Status = ERROR_INVALID_HANDLE;
  349. } else {
  350. Status = ERROR_SUCCESS;
  351. }
  352. if( Status != ERROR_SUCCESS )
  353. {
  354. //
  355. // if we haven't logged the error yet, log it
  356. //
  357. if (!sfErrReported)
  358. {
  359. REPORT_ERROR(DHCP_COLLECT_ERR, LOG_USER);
  360. sfErrReported = TRUE;
  361. }
  362. //
  363. // Error retrieving statistics.
  364. //
  365. *lpcbTotalBytes = 0;
  366. *lpNumObjectTypes = 0;
  367. return NO_ERROR;
  368. }
  369. //
  370. // Ahaa, we got the statistics, reset flag if set
  371. //
  372. if (sfErrReported)
  373. {
  374. sfErrReported = FALSE;
  375. }
  376. //
  377. // Format the DHCP Server data.
  378. //
  379. pCounterBlock = (DHCPDATA_COUNTER_BLOCK *)( pDhcpDataDataDefinition + 1 );
  380. pCounterBlock->PerfCounterBlock.ByteLength =
  381. DHCPDATA_SIZE_OF_PERFORMANCE_DATA;
  382. //
  383. // Get the pointer to the first (DWORD) counter. This
  384. // pointer *must* be quadword aligned.
  385. //
  386. pdwCounter = (DWORD *)( pCounterBlock + 1 );
  387. ASSERT( ( (DWORD_PTR)pdwCounter & 3 ) == 0 );
  388. //
  389. // Move the DWORDs into the buffer.
  390. //
  391. PerfStats = *SharedMem;
  392. PerfStats.dwNumMilliSecondsProcessed /= (
  393. 1 + PerfStats.dwNumPacketsProcessed
  394. );
  395. memcpy( (LPBYTE)pdwCounter, (LPBYTE)&PerfStats, sizeof(ULONG)*NUMBER_OF_DHCPDATA_COUNTERS);
  396. pdwCounter += NUMBER_OF_DHCPDATA_COUNTERS;
  397. //
  398. // Update arguments for return.
  399. //
  400. *lppData = (PVOID)pdwCounter;
  401. *lpNumObjectTypes = 1;
  402. *lpcbTotalBytes = (DWORD)((BYTE *)pdwCounter - (BYTE *)pDhcpDataDataDefinition);
  403. //
  404. // Success! Honest!!
  405. //
  406. REPORT_INFORMATION( DHCP_COLLECT_SUCCESS, LOG_VERBOSE );
  407. return NO_ERROR;
  408. } // CollectDHCPPerformanceData
  409. /*******************************************************************
  410. NAME: CloseDHCPPerformanceData
  411. SYNOPSIS: Terminates the performance counters.
  412. RETURNS: DWORD - Win32 status code.
  413. HISTORY:
  414. KeithMo 07-Jun-1993 Created.
  415. ********************************************************************/
  416. DWORD CloseDhcpPerformanceData( VOID )
  417. {
  418. LONG lOpens;
  419. //
  420. // No real cleanup to do here.
  421. //
  422. REPORT_INFORMATION( DHCP_CLOSE_ENTERED, LOG_VERBOSE );
  423. //
  424. // NOTE: The interlocked operations are used just as a safeguard.
  425. // As with all perflibs, these 3 functions should be called within
  426. // a data mutex.
  427. //
  428. lOpens = InterlockedDecrement(&cOpens);
  429. assert (lOpens >= 0);
  430. if (lOpens == 0)
  431. {
  432. //
  433. // unbind from the nameserver. There could be synch. problems since
  434. // sfLogOpen is changed in both Open and Close functions. This at the
  435. // max. will affect logging. It being unclear at this point whether or
  436. // not Open gets called multiple times (from all looks of it, it is only
  437. // called once), this flag may even not be necessary.
  438. //
  439. MonCloseEventLog();
  440. sfLogOpen = FALSE;
  441. CleanupSharedMem();
  442. }
  443. return NO_ERROR;
  444. } // CloseDHCPPerformanceData