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.

769 lines
20 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1999
  6. //
  7. // File: perfmon.c
  8. //
  9. // Contents: Schannel performance counter functions.
  10. //
  11. // Functions:
  12. //
  13. // History: 04-11-2000 jbanes Created
  14. //
  15. //------------------------------------------------------------------------
  16. #include "sslp.h"
  17. #include "perfmon.h"
  18. DWORD dwOpenCount = 0; // count of "Open" threads
  19. BOOL bInitOK = FALSE; // true = DLL initialized OK
  20. HANDLE LsaHandle;
  21. DWORD PackageNumber;
  22. PM_OPEN_PROC OpenSslPerformanceData;
  23. PM_COLLECT_PROC CollectSslPerformanceData;
  24. PM_CLOSE_PROC CloseSslPerformanceData;
  25. #define DWORD_MULTIPLE(x) (((x+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD))
  26. SSLPERF_DATA_DEFINITION SslPerfDataDefinition =
  27. {
  28. // PERF_OBJECT_TYPE
  29. {
  30. sizeof(SSLPERF_DATA_DEFINITION) + sizeof(SSLPERF_COUNTER),
  31. sizeof(SSLPERF_DATA_DEFINITION),
  32. sizeof(PERF_OBJECT_TYPE),
  33. SSLPERF_OBJ,
  34. 0,
  35. SSLPERF_OBJ,
  36. 0,
  37. PERF_DETAIL_NOVICE,
  38. (sizeof(SSLPERF_DATA_DEFINITION) - sizeof(PERF_OBJECT_TYPE)) /
  39. sizeof(PERF_COUNTER_DEFINITION),
  40. 0
  41. PERF_NO_INSTANCES,
  42. 0
  43. },
  44. // PERF_COUNTER_DEFINITION
  45. {
  46. sizeof(PERF_COUNTER_DEFINITION),
  47. SSL_CACHE_ENTRIES,
  48. 0,
  49. SSL_CACHE_ENTRIES,
  50. 0,
  51. 0,
  52. PERF_DETAIL_NOVICE,
  53. PERF_COUNTER_RAWCOUNT,
  54. sizeof(DWORD),
  55. FIELD_OFFSET(SSLPERF_COUNTER, dwCacheEntries)
  56. },
  57. // PERF_COUNTER_DEFINITION
  58. {
  59. sizeof(PERF_COUNTER_DEFINITION),
  60. SSL_ACTIVE_ENTRIES,
  61. 0,
  62. SSL_ACTIVE_ENTRIES,
  63. 0,
  64. 0,
  65. PERF_DETAIL_NOVICE,
  66. PERF_COUNTER_RAWCOUNT,
  67. sizeof(DWORD),
  68. FIELD_OFFSET(SSLPERF_COUNTER, dwActiveEntries)
  69. },
  70. // PERF_COUNTER_DEFINITION
  71. {
  72. sizeof(PERF_COUNTER_DEFINITION),
  73. SSL_HANDSHAKE_COUNT,
  74. 0,
  75. SSL_HANDSHAKE_COUNT,
  76. 0,
  77. 0,
  78. PERF_DETAIL_NOVICE,
  79. PERF_COUNTER_COUNTER,
  80. sizeof(DWORD),
  81. FIELD_OFFSET(SSLPERF_COUNTER, dwHandshakeCount)
  82. },
  83. // PERF_COUNTER_DEFINITION
  84. {
  85. sizeof(PERF_COUNTER_DEFINITION),
  86. SSL_RECONNECT_COUNT,
  87. 0,
  88. SSL_RECONNECT_COUNT,
  89. 0,
  90. 0,
  91. PERF_DETAIL_NOVICE,
  92. PERF_COUNTER_COUNTER,
  93. sizeof(DWORD),
  94. FIELD_OFFSET(SSLPERF_COUNTER, dwReconnectCount)
  95. }
  96. };
  97. typedef struct _INSTANCE_DATA
  98. {
  99. DWORD dwProtocol;
  100. LPWSTR szInstanceName;
  101. } INSTANCE_DATA, *PINSTANCE_DATA;
  102. static INSTANCE_DATA wdInstance[] =
  103. {
  104. {SP_PROT_CLIENTS, L"Client"},
  105. {SP_PROT_SERVERS, L"Server"},
  106. {0, L"_Total"}
  107. };
  108. static const DWORD NUM_INSTANCES =
  109. (sizeof(wdInstance)/sizeof(wdInstance[0]));
  110. /*++
  111. Routine Description:
  112. This routine will initialize the data structures used to pass
  113. data back to the registry
  114. Arguments:
  115. Pointer to object ID of each device to be opened (PerfGen)
  116. Return Value:
  117. None.
  118. --*/
  119. DWORD APIENTRY
  120. OpenSslPerformanceData(
  121. LPWSTR lpDeviceNames)
  122. {
  123. LONG Status;
  124. HKEY hKey = 0;
  125. DWORD size;
  126. DWORD type;
  127. DWORD dwFirstCounter;
  128. DWORD dwFirstHelp;
  129. LSA_STRING PackageName;
  130. UNREFERENCED_PARAMETER(lpDeviceNames);
  131. //
  132. // Since WINLOGON 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. if (!dwOpenCount)
  141. {
  142. // get counter and help index base values from registry
  143. // Open key to registry entry
  144. // read First Counter and First Help values
  145. // update static data strucutures by adding base to
  146. // offset value in structure.
  147. Status = RegOpenKeyExA(
  148. HKEY_LOCAL_MACHINE,
  149. "SYSTEM\\CurrentControlSet\\Services\\Schannel\\Performance",
  150. 0L,
  151. KEY_READ,
  152. &hKey);
  153. if(Status != ERROR_SUCCESS)
  154. {
  155. // this is fatal, if we can't get the base values of the
  156. // counter or help names, then the names won't be available
  157. // to the requesting application so there's not much
  158. // point in continuing.
  159. goto cleanup;
  160. }
  161. size = sizeof (DWORD);
  162. Status = RegQueryValueExA(
  163. hKey,
  164. "First Counter",
  165. 0L,
  166. &type,
  167. (LPBYTE)&dwFirstCounter,
  168. &size);
  169. if(Status != ERROR_SUCCESS)
  170. {
  171. // this is fatal, if we can't get the base values of the
  172. // counter or help names, then the names won't be available
  173. // to the requesting application so there's not much
  174. // point in continuing.
  175. goto cleanup;
  176. }
  177. size = sizeof (DWORD);
  178. Status = RegQueryValueExA(
  179. hKey,
  180. "First Help",
  181. 0L,
  182. &type,
  183. (LPBYTE)&dwFirstHelp,
  184. &size);
  185. if(Status != ERROR_SUCCESS)
  186. {
  187. // this is fatal, if we can't get the base values of the
  188. // counter or help names, then the names won't be available
  189. // to the requesting application so there's not much
  190. // point in continuing.
  191. goto cleanup;
  192. }
  193. //
  194. // NOTE: the initialization program could also retrieve
  195. // LastCounter and LastHelp if they wanted to do
  196. // bounds checking on the new number. e.g.
  197. //
  198. // counter->CounterNameTitleIndex += dwFirstCounter;
  199. // if (counter->CounterNameTitleIndex > dwLastCounter) {
  200. // LogErrorToEventLog (INDEX_OUT_OF_BOUNDS);
  201. // }
  202. //
  203. // Establish connection to schannel.
  204. //
  205. Status = LsaConnectUntrusted(&LsaHandle);
  206. if(!NT_SUCCESS(Status))
  207. {
  208. goto cleanup;
  209. }
  210. PackageName.Buffer = UNISP_NAME_A;
  211. PackageName.Length = (USHORT)strlen(PackageName.Buffer);
  212. PackageName.MaximumLength = PackageName.Length + 1;
  213. Status = LsaLookupAuthenticationPackage(
  214. LsaHandle,
  215. &PackageName,
  216. &PackageNumber);
  217. if(FAILED(Status))
  218. {
  219. CloseHandle(LsaHandle);
  220. goto cleanup;
  221. }
  222. //
  223. // Initialize the performance counters.
  224. //
  225. SslPerfDataDefinition.SslPerfObjectType.ObjectNameTitleIndex += dwFirstCounter;
  226. SslPerfDataDefinition.SslPerfObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  227. // assign index of default counter (Sine Wave)
  228. SslPerfDataDefinition.SslPerfObjectType.DefaultCounter = 0;
  229. SslPerfDataDefinition.CacheEntriesDef.CounterNameTitleIndex += dwFirstCounter;
  230. SslPerfDataDefinition.CacheEntriesDef.CounterHelpTitleIndex += dwFirstHelp;
  231. SslPerfDataDefinition.ActiveEntriesDef.CounterNameTitleIndex += dwFirstCounter;
  232. SslPerfDataDefinition.ActiveEntriesDef.CounterHelpTitleIndex += dwFirstHelp;
  233. SslPerfDataDefinition.HandshakeCountDef.CounterNameTitleIndex += dwFirstCounter;
  234. SslPerfDataDefinition.HandshakeCountDef.CounterHelpTitleIndex += dwFirstHelp;
  235. SslPerfDataDefinition.ReconnectCountDef.CounterNameTitleIndex += dwFirstCounter;
  236. SslPerfDataDefinition.ReconnectCountDef.CounterHelpTitleIndex += dwFirstHelp;
  237. bInitOK = TRUE;
  238. }
  239. dwOpenCount++;
  240. Status = ERROR_SUCCESS;
  241. cleanup:
  242. if(hKey)
  243. {
  244. RegCloseKey(hKey);
  245. }
  246. return Status;
  247. }
  248. DWORD
  249. GetCacheInfo(
  250. PSSL_PERFMON_INFO_RESPONSE pPerfmonInfo)
  251. {
  252. PSSL_PERFMON_INFO_REQUEST pRequest = NULL;
  253. PSSL_PERFMON_INFO_RESPONSE pResponse = NULL;
  254. DWORD cbResponse = 0;
  255. NTSTATUS SubStatus;
  256. NTSTATUS Status;
  257. pRequest = (PSSL_PERFMON_INFO_REQUEST)LocalAlloc(LPTR, sizeof(SSL_PERFMON_INFO_REQUEST));
  258. if(pRequest == NULL)
  259. {
  260. Status = STATUS_INSUFFICIENT_RESOURCES;
  261. goto cleanup;
  262. }
  263. pRequest->MessageType = SSL_PERFMON_INFO_MESSAGE;
  264. Status = LsaCallAuthenticationPackage(
  265. LsaHandle,
  266. PackageNumber,
  267. pRequest,
  268. sizeof(SSL_PERFMON_INFO_REQUEST),
  269. &pResponse,
  270. &cbResponse,
  271. &SubStatus);
  272. if(FAILED(Status))
  273. {
  274. goto cleanup;
  275. }
  276. *pPerfmonInfo = *pResponse;
  277. Status = STATUS_SUCCESS;
  278. cleanup:
  279. if(pRequest)
  280. {
  281. LocalFree(pRequest);
  282. }
  283. if (pResponse != NULL)
  284. {
  285. LsaFreeReturnBuffer(pResponse);
  286. }
  287. return Status;
  288. }
  289. /*++
  290. Routine Description:
  291. This routine will return the data for the ssl performance counters.
  292. Arguments:
  293. IN LPWSTR lpValueName
  294. pointer to a wide character string passed by registry.
  295. IN OUT LPVOID *lppData
  296. IN: pointer to the address of the buffer to receive the completed
  297. PerfDataBlock and subordinate structures. This routine will
  298. append its data to the buffer starting at the point referenced
  299. by *lppData.
  300. OUT: points to the first byte after the data structure added by this
  301. routine. This routine updated the value at lppdata after appending
  302. its data.
  303. IN OUT LPDWORD lpcbTotalBytes
  304. IN: the address of the DWORD that tells the size in bytes of the
  305. buffer referenced by the lppData argument
  306. OUT: the number of bytes added by this routine is writted to the
  307. DWORD pointed to by this argument
  308. IN OUT LPDWORD NumObjectTypes
  309. IN: the address of the DWORD to receive the number of objects added
  310. by this routine
  311. OUT: the number of objects added by this routine is writted to the
  312. DWORD pointed to by this argument
  313. Return Value:
  314. ERROR_MORE_DATA if buffer passed is too small to hold data.
  315. ERROR_SUCCESS if success or any other error.
  316. --*/
  317. DWORD APIENTRY
  318. CollectSslPerformanceData(
  319. IN LPWSTR lpValueName,
  320. IN OUT LPVOID *lppData,
  321. IN OUT LPDWORD lpcbTotalBytes,
  322. IN OUT LPDWORD lpNumObjectTypes)
  323. {
  324. PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition;
  325. SSLPERF_DATA_DEFINITION *pSslPerfDataDefinition;
  326. PSSLPERF_COUNTER pSC;
  327. SSL_PERFMON_INFO_RESPONSE PerfmonInfo;
  328. DWORD dwThisInstance;
  329. ULONG SpaceNeeded;
  330. DWORD dwQueryType;
  331. DWORD Status;
  332. //
  333. // before doing anything else, see if Open went OK
  334. //
  335. if (!bInitOK)
  336. {
  337. // unable to continue because open failed.
  338. *lpcbTotalBytes = (DWORD) 0;
  339. *lpNumObjectTypes = (DWORD) 0;
  340. return ERROR_SUCCESS; // yes, this is a successful exit
  341. }
  342. //
  343. // see if this is a foreign (i.e. non-NT) computer data request
  344. //
  345. dwQueryType = GetQueryType (lpValueName);
  346. if (dwQueryType == QUERY_FOREIGN)
  347. {
  348. // this routine does not service requests for data from
  349. // Non-NT computers
  350. *lpcbTotalBytes = (DWORD) 0;
  351. *lpNumObjectTypes = (DWORD) 0;
  352. return ERROR_SUCCESS;
  353. }
  354. if (dwQueryType == QUERY_ITEMS)
  355. {
  356. if(!(IsNumberInUnicodeList(SslPerfDataDefinition.SslPerfObjectType.ObjectNameTitleIndex, lpValueName)))
  357. {
  358. // request received for data object not provided by this routine
  359. *lpcbTotalBytes = (DWORD) 0;
  360. *lpNumObjectTypes = (DWORD) 0;
  361. return ERROR_SUCCESS;
  362. }
  363. }
  364. pSslPerfDataDefinition = (SSLPERF_DATA_DEFINITION *) *lppData;
  365. SpaceNeeded = sizeof(SSLPERF_DATA_DEFINITION) +
  366. (NUM_INSTANCES * (sizeof(PERF_INSTANCE_DEFINITION) +
  367. (24) + // size of instance names
  368. sizeof (SSLPERF_COUNTER)));
  369. if ( *lpcbTotalBytes < SpaceNeeded )
  370. {
  371. *lpcbTotalBytes = (DWORD) 0;
  372. *lpNumObjectTypes = (DWORD) 0;
  373. return ERROR_MORE_DATA;
  374. }
  375. //
  376. // Copy the (constant, initialized) Object Type and counter definitions
  377. // to the caller's data buffer
  378. //
  379. memmove(pSslPerfDataDefinition,
  380. &SslPerfDataDefinition,
  381. sizeof(SSLPERF_DATA_DEFINITION));
  382. //
  383. // Get info from schannel.
  384. //
  385. Status = GetCacheInfo(&PerfmonInfo);
  386. if(!NT_SUCCESS(Status))
  387. {
  388. *lpcbTotalBytes = (DWORD) 0;
  389. *lpNumObjectTypes = (DWORD) 0;
  390. return ERROR_SUCCESS;
  391. }
  392. //
  393. // Create data for return for each instance
  394. //
  395. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  396. &pSslPerfDataDefinition[1];
  397. for(dwThisInstance = 0; dwThisInstance < NUM_INSTANCES; dwThisInstance++)
  398. {
  399. MonBuildInstanceDefinition(
  400. pPerfInstanceDefinition,
  401. (PVOID *)&pSC,
  402. 0,
  403. 0,
  404. (DWORD)-1, // use name
  405. wdInstance[dwThisInstance].szInstanceName);
  406. pSC->CounterBlock.ByteLength = sizeof (SSLPERF_COUNTER);
  407. if(wdInstance[dwThisInstance].dwProtocol & SP_PROT_CLIENTS)
  408. {
  409. // client
  410. pSC->dwCacheEntries = PerfmonInfo.ClientCacheEntries;
  411. pSC->dwActiveEntries = PerfmonInfo.ClientActiveEntries;
  412. pSC->dwHandshakeCount = PerfmonInfo.ClientHandshakesPerSecond;
  413. pSC->dwReconnectCount = PerfmonInfo.ClientReconnectsPerSecond;
  414. }
  415. else if(wdInstance[dwThisInstance].dwProtocol & SP_PROT_SERVERS)
  416. {
  417. // server
  418. pSC->dwCacheEntries = PerfmonInfo.ServerCacheEntries;
  419. pSC->dwActiveEntries = PerfmonInfo.ServerActiveEntries;
  420. pSC->dwHandshakeCount = PerfmonInfo.ServerHandshakesPerSecond;
  421. pSC->dwReconnectCount = PerfmonInfo.ServerReconnectsPerSecond;
  422. }
  423. else
  424. {
  425. // total
  426. pSC->dwCacheEntries = PerfmonInfo.ClientCacheEntries +
  427. PerfmonInfo.ServerCacheEntries;
  428. pSC->dwActiveEntries = PerfmonInfo.ClientActiveEntries +
  429. PerfmonInfo.ServerActiveEntries;
  430. pSC->dwHandshakeCount = PerfmonInfo.ClientHandshakesPerSecond +
  431. PerfmonInfo.ServerHandshakesPerSecond;
  432. pSC->dwReconnectCount = PerfmonInfo.ClientReconnectsPerSecond +
  433. PerfmonInfo.ServerReconnectsPerSecond;
  434. }
  435. // update instance pointer for next instance
  436. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pSC[1];
  437. }
  438. //
  439. // update arguments for return
  440. //
  441. *lppData = (PVOID)pPerfInstanceDefinition;
  442. *lpNumObjectTypes = 1;
  443. pSslPerfDataDefinition->SslPerfObjectType.TotalByteLength =
  444. *lpcbTotalBytes = (DWORD)((LONG_PTR)pPerfInstanceDefinition -
  445. (LONG_PTR)pSslPerfDataDefinition);
  446. // update instance count
  447. pSslPerfDataDefinition->SslPerfObjectType.NumInstances = NUM_INSTANCES;
  448. return ERROR_SUCCESS;
  449. }
  450. /*++
  451. Routine Description:
  452. This routine closes the open handles to the Signal Gen counters.
  453. Arguments:
  454. None.
  455. Return Value:
  456. ERROR_SUCCESS
  457. --*/
  458. DWORD APIENTRY
  459. CloseSslPerformanceData(void)
  460. {
  461. if(--dwOpenCount == 0)
  462. {
  463. // when this is the last thread...
  464. if(LsaHandle)
  465. {
  466. CloseHandle(LsaHandle);
  467. }
  468. }
  469. return ERROR_SUCCESS;
  470. }
  471. /*++
  472. GetQueryType
  473. returns the type of query described in the lpValue string so that
  474. the appropriate processing method may be used
  475. Arguments
  476. IN lpValue
  477. string passed to PerfRegQuery Value for processing
  478. Return Value
  479. QUERY_GLOBAL
  480. if lpValue == 0 (null pointer)
  481. lpValue == pointer to Null string
  482. lpValue == pointer to "Global" string
  483. QUERY_FOREIGN
  484. if lpValue == pointer to "Foreign" string
  485. QUERY_COSTLY
  486. if lpValue == pointer to "Costly" string
  487. otherwise:
  488. QUERY_ITEMS
  489. --*/
  490. DWORD
  491. GetQueryType (
  492. IN LPWSTR lpValue)
  493. {
  494. if(lpValue == NULL || *lpValue == 0)
  495. {
  496. return QUERY_GLOBAL;
  497. }
  498. if(lstrcmp(lpValue, L"Global") == 0)
  499. {
  500. return QUERY_GLOBAL;
  501. }
  502. if(lstrcmp(lpValue, L"Foreign") == 0)
  503. {
  504. return QUERY_FOREIGN;
  505. }
  506. if(lstrcmp(lpValue, L"Costly") == 0)
  507. {
  508. return QUERY_COSTLY;
  509. }
  510. // if not Global and not Foreign and not Costly,
  511. // then it must be an item list
  512. return QUERY_ITEMS;
  513. }
  514. /*++
  515. MonBuildInstanceDefinition - Build an instance of an object
  516. Inputs:
  517. pBuffer - pointer to buffer where instance is to
  518. be constructed
  519. pBufferNext - pointer to a pointer which will contain
  520. next available location, DWORD aligned
  521. ParentObjectTitleIndex
  522. - Title Index of parent object type; 0 if
  523. no parent object
  524. ParentObjectInstance
  525. - Index into instances of parent object
  526. type, starting at 0, for this instances
  527. parent object instance
  528. UniqueID - a unique identifier which should be used
  529. instead of the Name for identifying
  530. this instance
  531. Name - Name of this instance
  532. --*/
  533. BOOL
  534. MonBuildInstanceDefinition(
  535. PERF_INSTANCE_DEFINITION *pBuffer,
  536. PVOID *pBufferNext,
  537. DWORD ParentObjectTitleIndex,
  538. DWORD ParentObjectInstance,
  539. DWORD UniqueID,
  540. LPWSTR Name)
  541. {
  542. DWORD NameLength;
  543. LPWSTR pName;
  544. // Include trailing null in name size
  545. NameLength = (lstrlenW(Name) + 1) * sizeof(WCHAR);
  546. pBuffer->ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
  547. DWORD_MULTIPLE(NameLength);
  548. pBuffer->ParentObjectTitleIndex = ParentObjectTitleIndex;
  549. pBuffer->ParentObjectInstance = ParentObjectInstance;
  550. pBuffer->UniqueID = UniqueID;
  551. pBuffer->NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
  552. pBuffer->NameLength = NameLength;
  553. // copy name to name buffer
  554. pName = (LPWSTR)&pBuffer[1];
  555. RtlMoveMemory(pName,Name,NameLength);
  556. // update "next byte" pointer
  557. *pBufferNext = (PVOID) ((PCHAR) pBuffer + pBuffer->ByteLength);
  558. return 0;
  559. }
  560. /*++
  561. IsNumberInUnicodeList
  562. Arguments:
  563. IN dwNumber
  564. DWORD number to find in list
  565. IN lpwszUnicodeList
  566. Null terminated, Space delimited list of decimal numbers
  567. Return Value:
  568. TRUE:
  569. dwNumber was found in the list of unicode number strings
  570. FALSE:
  571. dwNumber was not found in the list.
  572. --*/
  573. BOOL
  574. IsNumberInUnicodeList(
  575. IN DWORD dwNumber,
  576. IN LPWSTR lpwszUnicodeList)
  577. {
  578. DWORD dwThisNumber;
  579. DWORD cDigits;
  580. if(lpwszUnicodeList == 0) return FALSE;
  581. while(TRUE)
  582. {
  583. // Skip over leading whitespace.
  584. while(*lpwszUnicodeList && iswspace(*lpwszUnicodeList))
  585. {
  586. lpwszUnicodeList++;
  587. }
  588. // Get number.
  589. cDigits = 0;
  590. dwThisNumber = 0;
  591. while(iswdigit(*lpwszUnicodeList))
  592. {
  593. dwThisNumber *= 10;
  594. dwThisNumber += (*lpwszUnicodeList - L'0');
  595. cDigits++;
  596. lpwszUnicodeList++;
  597. }
  598. if(cDigits == 0)
  599. {
  600. return FALSE;
  601. }
  602. // Compare number to reference.
  603. if(dwThisNumber == dwNumber)
  604. {
  605. return TRUE;
  606. }
  607. }
  608. }