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.

736 lines
16 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // iasperf.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file implements the PerfMon DLL for the Everest server.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 09/15/1997 Original version.
  16. // 03/17/1998 Unmap the shared memory after each collection interval.
  17. // 06/18/1998 Unmap view of file after each collection interval.
  18. // 08/10/1998 Clean-up registration code.
  19. // 09/08/1997 Conform to latest rev. of ietf draft.
  20. // 09/11/1997 Use stats API. Add SNMP registration code.
  21. // 10/19/1998 Throw LONG's on error.
  22. // 01/18/1999 Do not register extension agent.
  23. // 02/11/1999 Ref. count open & close.
  24. // 05/13/1999 Unload previous counters before loading new ones.
  25. // 09/23/1999 Don't create files from resource.
  26. // 01/25/2000 Check if DLL is opend during Collect.
  27. // 02/18/2000 Added support for proxy counters.
  28. //
  29. ///////////////////////////////////////////////////////////////////////////////
  30. #include <ias.h>
  31. #include <iasinfo.h>
  32. #include <iasutil.h>
  33. #include <loadperf.h>
  34. #include <newop.cpp>
  35. #include <iasperf.h>
  36. #include <perflib.h>
  37. #include <resource.h>
  38. #include <stats.h>
  39. //////////
  40. // Schema for the performance objects supported by this DLL.
  41. //////////
  42. extern PerfCollectorDef PERF_SCHEMA;
  43. //////////
  44. // The performance collector.
  45. //////////
  46. PerfCollector theCollector;
  47. //////////
  48. // Last start time of the server -- used to detect restarts.
  49. //////////
  50. LARGE_INTEGER theLastStart;
  51. //////////
  52. // Computes the server time counters.
  53. //////////
  54. PDWORD
  55. WINAPI
  56. ComputeServerTimes(
  57. PDWORD dst
  58. ) throw ()
  59. {
  60. if (theStats->seServer.liStartTime.QuadPart)
  61. {
  62. LARGE_INTEGER now, elapsed;
  63. GetSystemTimeAsFileTime((LPFILETIME)&now);
  64. elapsed.QuadPart = now.QuadPart - theStats->seServer.liStartTime.QuadPart;
  65. elapsed.QuadPart /= 10000000;
  66. *dst++ = elapsed.LowPart;
  67. elapsed.QuadPart = now.QuadPart - theStats->seServer.liResetTime.QuadPart;
  68. elapsed.QuadPart /= 10000000;
  69. *dst++ = elapsed.LowPart;
  70. }
  71. else
  72. {
  73. // If the start time is zero, then the server's not running.
  74. *dst++ = 0;
  75. *dst++ = 0;
  76. }
  77. return dst;
  78. }
  79. //////////
  80. // Creates instances for any newly added clients.
  81. //////////
  82. VOID
  83. WINAPI
  84. PopulateInstances(
  85. PerfObjectType& sink
  86. ) throw ()
  87. {
  88. for (DWORD i = sink.size(); i < theStats->dwNumClients; ++i)
  89. {
  90. WCHAR buf[16];
  91. sink.addInstance(ias_inet_htow(theStats->ceClients[i].dwAddress, buf));
  92. }
  93. }
  94. //////////
  95. // Computes derived authentication counters from raw counters.
  96. //////////
  97. VOID
  98. WINAPI
  99. DeriveAuthCounters(
  100. PDWORD dst
  101. ) throw ()
  102. {
  103. // Compute packets received.
  104. DWORD rcvd = 0;
  105. for (DWORD i = 0; i < 6; ++i) rcvd += dst[i];
  106. dst[9] = rcvd;
  107. // Compute packets sent.
  108. DWORD sent = 0;
  109. for (DWORD j = 6; j < 9; ++j) sent += dst[j];
  110. dst[10] = sent;
  111. // Copy raw counters into rate counters.
  112. memcpy(dst + 11, dst, sizeof(DWORD) * 11);
  113. }
  114. //////////
  115. // Computes derived accounting counters from raw counters.
  116. //////////
  117. VOID
  118. WINAPI
  119. DeriveAcctCounters(
  120. PDWORD dst
  121. ) throw ()
  122. {
  123. // Compute packets received.
  124. DWORD rcvd = 0;
  125. for (DWORD i = 0; i < 7; ++i) rcvd += dst[i];
  126. dst[8] = rcvd;
  127. // Compute packets sent.
  128. DWORD sent = 0;
  129. for (DWORD j = 7; j < 8; ++j) sent += dst[j];
  130. dst[9] = sent;
  131. // Copy raw counters into rate counters.
  132. memcpy(dst + 10, dst, sizeof(DWORD) * 10);
  133. }
  134. //////////
  135. // Callback for the authentication server object.
  136. //////////
  137. VOID WINAPI AuthServerDataSource(PerfObjectType& sink)
  138. {
  139. PDWORD p = ComputeServerTimes(sink[0].getCounters());
  140. *p++ = theStats->seServer.dwCounters[radiusAuthServTotalInvalidRequests];
  141. *p++ = theStats->seServer.dwCounters[radiusAuthServTotalInvalidRequests];
  142. memset(p, 0, sizeof(DWORD) * 9);
  143. for (DWORD i = 0; i < theStats->dwNumClients; ++i)
  144. {
  145. for (DWORD j = 0; j < 9; ++j)
  146. {
  147. p[j] += theStats->ceClients[i].dwCounters[j];
  148. }
  149. }
  150. DeriveAuthCounters(p);
  151. }
  152. //////////
  153. // Callback for the authentication clients object.
  154. //////////
  155. VOID WINAPI AuthClientDataSource(PerfObjectType& sink)
  156. {
  157. PopulateInstances(sink);
  158. for (DWORD i = 0; i < theStats->dwNumClients; ++i)
  159. {
  160. PDWORD dst = sink[i].getCounters();
  161. memcpy(dst, theStats->ceClients[i].dwCounters, sizeof(DWORD) * 9);
  162. DeriveAuthCounters(dst);
  163. }
  164. }
  165. //////////
  166. // Callback for the accounting server object.
  167. //////////
  168. VOID WINAPI AcctServerDataSource(PerfObjectType& sink)
  169. {
  170. PDWORD p = ComputeServerTimes(sink[0].getCounters());
  171. *p++ = theStats->seServer.dwCounters[radiusAccServTotalInvalidRequests];
  172. *p++ = theStats->seServer.dwCounters[radiusAccServTotalInvalidRequests];
  173. memset(p, 0, sizeof(DWORD) * 8);
  174. for (DWORD i = 0; i < theStats->dwNumClients; ++i)
  175. {
  176. for (DWORD j = 0; j < 8; ++j)
  177. {
  178. p[j] += theStats->ceClients[i].dwCounters[j + 9];
  179. }
  180. }
  181. DeriveAcctCounters(p);
  182. }
  183. //////////
  184. // Callback for the accounting clients object.
  185. //////////
  186. VOID WINAPI AcctClientDataSource(PerfObjectType& sink)
  187. {
  188. PopulateInstances(sink);
  189. for (DWORD i = 0; i < theStats->dwNumClients; ++i)
  190. {
  191. PDWORD dst = sink[i].getCounters();
  192. memcpy(dst, theStats->ceClients[i].dwCounters + 9, sizeof(DWORD) * 8);
  193. DeriveAcctCounters(dst);
  194. }
  195. }
  196. //////////
  197. // Creates instances for any newly added remote servers.
  198. //////////
  199. VOID
  200. WINAPI
  201. PopulateServers(
  202. PerfObjectType& sink
  203. ) throw ()
  204. {
  205. for (DWORD i = sink.size(); i < theProxy->dwNumRemoteServers; ++i)
  206. {
  207. WCHAR buf[16];
  208. sink.addInstance(
  209. ias_inet_htow(theProxy->rseRemoteServers[i].dwAddress, buf)
  210. );
  211. }
  212. }
  213. VOID
  214. WINAPI
  215. DeriveProxyAuthCounters(
  216. PDWORD dst
  217. ) throw ()
  218. {
  219. // Compute packets received.
  220. dst[12] = + dst[radiusAuthClientAccessAccepts]
  221. + dst[radiusAuthClientAccessRejects]
  222. + dst[radiusAuthClientAccessChallenges]
  223. + dst[radiusAuthClientUnknownTypes];
  224. // Compute requests pending.
  225. dst[13] = + dst[radiusAuthClientAccessRequests]
  226. - dst[radiusAuthClientAccessAccepts]
  227. - dst[radiusAuthClientAccessRejects]
  228. - dst[radiusAuthClientAccessChallenges]
  229. + dst[radiusAuthClientMalformedAccessResponses]
  230. + dst[radiusAuthClientBadAuthenticators]
  231. + dst[radiusAuthClientPacketsDropped]
  232. - dst[radiusAuthClientTimeouts];
  233. // Copy raw counters into rate counters.
  234. memcpy(dst + 14, dst + 2, sizeof(DWORD) * 10);
  235. }
  236. VOID
  237. WINAPI
  238. DeriveProxyAcctCounters(
  239. PDWORD dst
  240. ) throw ()
  241. {
  242. // Compute packets received.
  243. dst[10] = + dst[radiusAccClientResponses - 12]
  244. + dst[radiusAccClientUnknownTypes - 12];
  245. // Compute requests pending.
  246. dst[11] = + dst[radiusAccClientRequests - 12]
  247. - dst[radiusAccClientResponses - 12]
  248. + dst[radiusAccClientMalformedResponses - 12]
  249. + dst[radiusAccClientBadAuthenticators - 12]
  250. + dst[radiusAccClientPacketsDropped - 12]
  251. - dst[radiusAccClientTimeouts - 12];
  252. // Copy raw counters into rate counters.
  253. memcpy(dst + 12, dst + 2, sizeof(DWORD) * 8);
  254. }
  255. //////////
  256. // Callback for the authentication proxy object.
  257. //////////
  258. VOID WINAPI AuthProxyDataSource(PerfObjectType& sink)
  259. {
  260. PDWORD p = sink[0].getCounters();
  261. p[0] = theProxy->peProxy.dwCounters[radiusAuthClientInvalidAddresses];
  262. p[1] = theProxy->peProxy.dwCounters[radiusAuthClientInvalidAddresses];
  263. memset(p + 2, 0, sizeof(DWORD) * 10);
  264. for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
  265. {
  266. for (DWORD j = 2; j < 12; ++j)
  267. {
  268. p[j] += theProxy->rseRemoteServers[i].dwCounters[j];
  269. }
  270. }
  271. DeriveProxyAuthCounters(p);
  272. }
  273. //////////
  274. // Callback for the accounting proxy object.
  275. //////////
  276. VOID WINAPI AcctProxyDataSource(PerfObjectType& sink)
  277. {
  278. PDWORD p = sink[0].getCounters();
  279. p[0] = theProxy->peProxy.dwCounters[radiusAccClientInvalidAddresses];
  280. p[1] = theProxy->peProxy.dwCounters[radiusAccClientInvalidAddresses];
  281. memset(p + 2, 0, sizeof(DWORD) * 8);
  282. for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
  283. {
  284. for (DWORD j = 2; j < 10; ++j)
  285. {
  286. p[j] += theProxy->rseRemoteServers[i].dwCounters[j + 12];
  287. }
  288. }
  289. DeriveProxyAcctCounters(p);
  290. }
  291. //////////
  292. // Callback for the remote authentication servers.
  293. //////////
  294. VOID WINAPI AuthRemoteServerDataSource(PerfObjectType& sink)
  295. {
  296. PopulateServers(sink);
  297. for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
  298. {
  299. PDWORD dst = sink[i].getCounters();
  300. memcpy(
  301. dst,
  302. theProxy->rseRemoteServers[i].dwCounters,
  303. sizeof(DWORD) * 12
  304. );
  305. DeriveProxyAuthCounters(dst);
  306. }
  307. }
  308. //////////
  309. // Callback for the remote accounting servers.
  310. //////////
  311. VOID WINAPI AcctRemoteServerDataSource(PerfObjectType& sink)
  312. {
  313. PopulateServers(sink);
  314. for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
  315. {
  316. PDWORD dst = sink[i].getCounters();
  317. memcpy(
  318. dst,
  319. theProxy->rseRemoteServers[i].dwCounters + 12,
  320. sizeof(DWORD) * 10
  321. );
  322. DeriveProxyAcctCounters(dst);
  323. }
  324. }
  325. //////////
  326. // Reference count for API initialization.
  327. //////////
  328. LONG theRefCount;
  329. //////////
  330. // Serialize access to PerfMon.
  331. //////////
  332. CRITICAL_SECTION thePerfLock;
  333. ///////////////////////////////////////////////////////////////////////////////
  334. //
  335. // FUNCTION
  336. //
  337. // OpenPerformanceData
  338. //
  339. ///////////////////////////////////////////////////////////////////////////////
  340. extern "C"
  341. DWORD
  342. WINAPI
  343. OpenPerformanceData(
  344. LPWSTR lpDeviceNames
  345. )
  346. {
  347. EnterCriticalSection(&thePerfLock);
  348. DWORD error = NO_ERROR;
  349. // Are we already initialized?
  350. if (theRefCount == 0)
  351. {
  352. if (StatsOpen())
  353. {
  354. try
  355. {
  356. theCollector.open(PERF_SCHEMA);
  357. // Everything succeeded, so update theRefCount.
  358. theRefCount = 1;
  359. }
  360. catch (LONG lErr)
  361. {
  362. StatsClose();
  363. error = (DWORD)lErr;
  364. }
  365. }
  366. else
  367. {
  368. error = GetLastError();
  369. }
  370. }
  371. else
  372. {
  373. // Already initialized, so just bump the ref. count.
  374. ++theRefCount;
  375. }
  376. LeaveCriticalSection(&thePerfLock);
  377. return error;
  378. }
  379. ///////////////////////////////////////////////////////////////////////////////
  380. //
  381. // FUNCTION
  382. //
  383. // CollectPerformanceData
  384. //
  385. ///////////////////////////////////////////////////////////////////////////////
  386. extern "C"
  387. DWORD
  388. WINAPI
  389. CollectPerformanceData(
  390. LPWSTR lpwszValue,
  391. LPVOID* lppData,
  392. LPDWORD lpcbBytes,
  393. LPDWORD lpcObjectTypes
  394. )
  395. {
  396. DWORD error = NO_ERROR;
  397. EnterCriticalSection(&thePerfLock);
  398. if (theRefCount)
  399. {
  400. StatsLock();
  401. // If the server has restarted, then
  402. if (theStats->seServer.liStartTime.QuadPart != theLastStart.QuadPart)
  403. {
  404. // ... clear out any old instances.
  405. theCollector.clear();
  406. theLastStart = theStats->seServer.liStartTime;
  407. }
  408. try
  409. {
  410. theCollector.collect(
  411. lpwszValue,
  412. *lppData,
  413. *lpcbBytes,
  414. *lpcObjectTypes
  415. );
  416. }
  417. catch (LONG lErr)
  418. {
  419. error = (DWORD)lErr;
  420. }
  421. StatsUnlock();
  422. }
  423. else
  424. {
  425. error = ERROR_NOT_READY;
  426. }
  427. LeaveCriticalSection(&thePerfLock);
  428. return error;
  429. }
  430. ///////////////////////////////////////////////////////////////////////////////
  431. //
  432. // FUNCTION
  433. //
  434. // ClosePerformanceData
  435. //
  436. ///////////////////////////////////////////////////////////////////////////////
  437. extern "C"
  438. DWORD
  439. WINAPI
  440. ClosePerformanceData()
  441. {
  442. EnterCriticalSection(&thePerfLock);
  443. DWORD error = NO_ERROR;
  444. if (--theRefCount == 0)
  445. {
  446. // We're the last man out, so clean-up.
  447. StatsClose();
  448. try
  449. {
  450. theCollector.close();
  451. }
  452. catch (LONG lErr)
  453. {
  454. error = (DWORD)lErr;
  455. }
  456. }
  457. LeaveCriticalSection(&thePerfLock);
  458. return error;
  459. }
  460. ///////////////////////////////////////////////////////////////////////////////
  461. //
  462. // FUNCTION
  463. //
  464. // CreateKey
  465. //
  466. // DESCRIPTION
  467. //
  468. // Creates a registry key.
  469. //
  470. ///////////////////////////////////////////////////////////////////////////////
  471. LONG
  472. WINAPI
  473. CreateKey(
  474. PCWSTR lpSubKey,
  475. PHKEY phkResult
  476. )
  477. {
  478. DWORD disposition;
  479. return RegCreateKeyExW(
  480. HKEY_LOCAL_MACHINE,
  481. lpSubKey,
  482. 0,
  483. NULL,
  484. REG_OPTION_NON_VOLATILE,
  485. KEY_SET_VALUE,
  486. NULL,
  487. phkResult,
  488. &disposition
  489. );
  490. }
  491. ///////////////////////////////////////////////////////////////////////////////
  492. //
  493. // FUNCTION
  494. //
  495. // SetStringValue
  496. //
  497. // DESCRIPTION
  498. //
  499. // Sets a string value on a registry key.
  500. //
  501. ///////////////////////////////////////////////////////////////////////////////
  502. LONG
  503. WINAPI
  504. SetStringValue(
  505. HKEY hKey,
  506. PCWSTR lpValueName,
  507. DWORD dwType,
  508. PCWSTR lpData
  509. )
  510. {
  511. return RegSetValueEx(
  512. hKey,
  513. lpValueName,
  514. 0,
  515. dwType,
  516. (CONST BYTE*)lpData,
  517. sizeof(WCHAR) * (wcslen(lpData) + 1)
  518. );
  519. }
  520. ///////////////////////////////////////////////////////////////////////////////
  521. //
  522. // FUNCTION
  523. //
  524. // DllRegisterServer
  525. //
  526. // DESCRIPTION
  527. //
  528. // Adds entries to the system registry.
  529. //
  530. ///////////////////////////////////////////////////////////////////////////////
  531. const WCHAR MODULE[] =
  532. L"%SystemRoot%\\System32\\iasperf.dll";
  533. const WCHAR PERF_KEY[] =
  534. L"SYSTEM\\CurrentControlSet\\Services\\IAS\\Performance";
  535. extern "C"
  536. STDAPI DllRegisterServer(void)
  537. {
  538. LONG error;
  539. HKEY hKey;
  540. DWORD disposition;
  541. //////////
  542. // Blow away the existing counters ...
  543. //////////
  544. UnloadPerfCounterTextStringsW(L"LODCTR " IASServiceName, TRUE);
  545. //////////
  546. // Update the PerfMon registry entries.
  547. //////////
  548. error = CreateKey(PERF_KEY, &hKey);
  549. if (error) { return HRESULT_FROM_WIN32(error); }
  550. SetStringValue(hKey, L"Library", REG_EXPAND_SZ, MODULE);
  551. SetStringValue(hKey, L"Open", REG_SZ, L"OpenPerformanceData");
  552. SetStringValue(hKey, L"Close", REG_SZ, L"ClosePerformanceData");
  553. SetStringValue(hKey, L"Collect", REG_SZ, L"CollectPerformanceData");
  554. RegCloseKey(hKey);
  555. //////////
  556. // Install the counters.
  557. //////////
  558. LONG ErrorCode = LoadPerfCounterTextStringsW(L"LODCTR IASPERF.INI", TRUE);
  559. if (ErrorCode == ERROR_ALREADY_EXISTS) { ErrorCode = NO_ERROR; }
  560. return HRESULT_FROM_WIN32(ErrorCode);
  561. }
  562. ///////////////////////////////////////////////////////////////////////////////
  563. //
  564. // FUNCTION
  565. //
  566. // DllUnregisterServer
  567. //
  568. // DESCRIPTION
  569. //
  570. // Removes entries from the system registry.
  571. //
  572. ///////////////////////////////////////////////////////////////////////////////
  573. extern "C"
  574. STDAPI DllUnregisterServer(void)
  575. {
  576. LONG error;
  577. HKEY hKey;
  578. /////////
  579. // Unload the text strings.
  580. /////////
  581. UnloadPerfCounterTextStringsW(L"LODCTR " IASServiceName, TRUE);
  582. //////////
  583. // Delete the PerfMon registry key.
  584. //////////
  585. error = RegOpenKeyExW(
  586. HKEY_LOCAL_MACHINE,
  587. L"SYSTEM\\CurrentControlSet\\Services\\IAS",
  588. 0,
  589. KEY_CREATE_SUB_KEY,
  590. &hKey
  591. );
  592. if (error == NO_ERROR)
  593. {
  594. RegDeleteKey(hKey, L"Performance");
  595. RegCloseKey(hKey);
  596. }
  597. return S_OK;
  598. }
  599. ///////////////////////////////////////////////////////////////////////////////
  600. //
  601. // FUNCTION
  602. //
  603. // DllMain
  604. //
  605. ///////////////////////////////////////////////////////////////////////////////
  606. extern "C"
  607. BOOL
  608. WINAPI
  609. DllMain(
  610. HINSTANCE hInstance,
  611. DWORD dwReason,
  612. LPVOID /*lpReserved*/
  613. )
  614. {
  615. if (dwReason == DLL_PROCESS_ATTACH)
  616. {
  617. DisableThreadLibraryCalls(hInstance);
  618. InitializeCriticalSectionAndSpinCount(&thePerfLock, 0x80001000);
  619. }
  620. else if (dwReason == DLL_PROCESS_DETACH)
  621. {
  622. DeleteCriticalSection(&thePerfLock);
  623. }
  624. return TRUE;
  625. }