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.

716 lines
16 KiB

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