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.

1814 lines
52 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. perrepsr.c
  5. Abstract:
  6. This file defines the server side of PERFMON support and contains the following :
  7. 1. Functions used to initialize the registry keys used by PERFMON.
  8. 2. Functions that are used by the File Replication Service
  9. to add and delete Object Instances (PERFMON) from the Registry
  10. and the hash tables (the basic hashing routines used here are
  11. defined in the file util\qhash.c).
  12. 3. Functions to create and use the hash tables which store data of
  13. the instance counters measured by PERFMON.
  14. 4. RPC server functions used by the performance dll (client) to collect
  15. data and send it to the PERFMON app.
  16. Author:
  17. Rohan Kumar [rohank] 13-Sept-1998
  18. David Orbits [Davidor} 6/Oct/98 - Revised. Changed nameing,
  19. changed registry query, eliminated mallocs, closed
  20. key handle leak, Moved priv funcs out of common
  21. header, general cleanup.
  22. Environment:
  23. User Mode Service
  24. Revision History:
  25. --*/
  26. //
  27. // Included below are the header file that contain the definition
  28. // of data structures used in the functions in this file. The header
  29. // file "perffrs.h" defines the RPC interface and is generated at compile
  30. // time by the build utility.
  31. //
  32. #include <perrepsr.h>
  33. #include <perffrs.h>
  34. #include "..\perfdll\repset.h"
  35. //
  36. // FRS_UniqueID and FRC_UniqueID are the Keys used to
  37. // hash in the counter data structures into the hash tables
  38. // for the Objects FILEREPLICASET and FILEREPLICACONN. They
  39. // are unique for every instance of the Objects.
  40. //
  41. ULONGLONG FRS_UniqueID = 1;
  42. ULONGLONG FRC_UniqueID = 1;
  43. //
  44. // The critical section object is used for acheiving mutual exclusion
  45. // when adding or deleting instances (the UniqueID variable has to be safe)
  46. //
  47. CRITICAL_SECTION *PerfmonLock = NULL;
  48. #define AcquirePerfmonLock EnterCriticalSection (PerfmonLock);
  49. #define ReleasePerfmonLock LeaveCriticalSection (PerfmonLock);
  50. //
  51. // Hash Table definitions
  52. //
  53. PQHASH_TABLE HTReplicaSet, HTReplicaConn;
  54. HANDLE PerfmonProcessSemaphore = INVALID_HANDLE_VALUE;
  55. //
  56. // The Context data structure used by the hash table enumeration routines
  57. //
  58. typedef struct _CONTEXT_DATA {
  59. PWCHAR name; // name of the Instance
  60. ULONGLONG KeyValue; // Key value of the Instance
  61. ULONG OBJType; // Object Type of the Instance
  62. } ContextData, *PContextData;
  63. #define MAX_CMD_LINE 256
  64. extern ReplicaSetValues RepSetInitData[FRS_NUMOFCOUNTERS];
  65. #undef GET_EXCEPTION_CODE
  66. #define GET_EXCEPTION_CODE(_x_) \
  67. { \
  68. (_x_) = GetExceptionCode(); \
  69. if (((LONG)(_x_)) < 0) { \
  70. (_x_) = FRS_ERR_INTERNAL_API; \
  71. } \
  72. /* NTFRSAPI_DBG_PRINT2("Exception caught: %d, 0x%08x\n", (_x_), (_x_)); */ \
  73. }
  74. //
  75. // The Total Instance
  76. //
  77. PHT_REPLICA_SET_DATA PMTotalInst = NULL;
  78. //
  79. // Internal functions
  80. //
  81. LONG
  82. PmInitPerfmonRegistryKeys(
  83. VOID
  84. );
  85. LONG
  86. PmInitializeRegistry (
  87. DWORD
  88. );
  89. ULONGLONG
  90. PmFindTheKeyValue(
  91. PContextData
  92. );
  93. VOID
  94. PmSetTheCOCounters(
  95. PHT_REPLICA_SET_DATA
  96. );
  97. DWORD
  98. PmHashFunction(
  99. PVOID,
  100. ULONG
  101. );
  102. DWORD
  103. PmSearchTable(
  104. PQHASH_TABLE,
  105. PQHASH_ENTRY,
  106. PQHASH_ENTRY,
  107. PVOID
  108. );
  109. VOID
  110. InitializePerfmonServer (
  111. VOID
  112. )
  113. /*++
  114. Routine Description:
  115. This routine inits the perfmon server for NTFRS.
  116. It inits the crit sect for the PerfmonLock variable
  117. It creates the hash tables of the specified size to store
  118. Instance counter values for the Objects. It also assigns the hash function
  119. to be used with each created table.
  120. It inits the perfmon registry keys.
  121. Arguments:
  122. none
  123. Return Value:
  124. none
  125. --*/
  126. {
  127. #undef DEBSUB
  128. #define DEBSUB "InitializePerfmonServer:"
  129. ULONG WStatus;
  130. //
  131. // Use a semaphore to ensure that only one process provides perfmon data.
  132. // A unique semaphore is only needed in test setup when we want
  133. // to run multiple copies of FRS on one machine and only want
  134. // one of the copies to register the perfmon interface.
  135. //
  136. if (RunningAsAService) {
  137. PerfmonProcessSemaphore = CreateSemaphoreW(NULL,
  138. 0,
  139. 0x7fffffff,
  140. NULL);
  141. }else{
  142. PerfmonProcessSemaphore = CreateSemaphoreW(NULL,
  143. 0,
  144. 0x7fffffff,
  145. L"NTFRS_Sempahore_");
  146. }
  147. WStatus = GetLastError();
  148. if (!HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
  149. PerfmonProcessSemaphore = INVALID_HANDLE_VALUE;
  150. DPRINT_WS(0,"CreateSemaphore returned", WStatus);
  151. return;
  152. }
  153. if (WIN_ALREADY_EXISTS(WStatus)) {
  154. FRS_CLOSE(PerfmonProcessSemaphore);
  155. DPRINT(0,"PerfmonProcessSemaphore already exists\n");
  156. return;
  157. }
  158. //
  159. // Allocate memory for the lock
  160. //
  161. PerfmonLock = (CRITICAL_SECTION *) FrsAlloc (sizeof(CRITICAL_SECTION));
  162. //
  163. // Initialize the critical section object
  164. //
  165. INITIALIZE_CRITICAL_SECTION(PerfmonLock);
  166. //
  167. // create the hash tables and assign the hash functions. One table
  168. // for replica set objects and one for connection objects.
  169. //
  170. HTReplicaSet = FrsAllocTypeSize(QHASH_TABLE_TYPE, HASHTABLESIZE);
  171. SET_QHASH_TABLE_HASH_CALC(HTReplicaSet, PmHashFunction);
  172. HTReplicaConn = FrsAllocTypeSize(QHASH_TABLE_TYPE, HASHTABLESIZE);
  173. SET_QHASH_TABLE_HASH_CALC(HTReplicaConn, PmHashFunction);
  174. }
  175. VOID
  176. ShutdownPerfmonServer (
  177. VOID
  178. )
  179. /*++
  180. Routine Description:
  181. This routine is called by the application just before it ends
  182. Arguments:
  183. none
  184. Return Value:
  185. none
  186. --*/
  187. {
  188. #undef DEBSUB
  189. #define DEBSUB "ShutdownPerfmonServer:"
  190. if (HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
  191. if (PerfmonLock != NULL) {
  192. //
  193. // Delete the critical section object & Free the allocated memory
  194. //
  195. DeleteCriticalSection (PerfmonLock);
  196. PerfmonLock = FrsFree (PerfmonLock);
  197. }
  198. //
  199. // Free the hash tables.
  200. //
  201. HTReplicaSet = FrsFreeType (HTReplicaSet);
  202. HTReplicaConn = FrsFreeType (HTReplicaConn);
  203. //
  204. // Close the semaphore handle.
  205. //
  206. FRS_CLOSE(PerfmonProcessSemaphore);
  207. }
  208. }
  209. DWORD
  210. PmHashFunction (
  211. IN PVOID Qkey,
  212. IN ULONG len
  213. )
  214. /*++
  215. Routine Description:
  216. This is the hashing function used by the functions that Lookup,
  217. Add or Delete entries from the Hash Tables. The Key is a 64 bit
  218. number and the hashing function casts it to a 32 bit number and
  219. returns it as the hash value.
  220. Arguments:
  221. QKey - Pointer to the Key to be hashed.
  222. len - Length of QKey (unused here).
  223. Return Value:
  224. The hashed value of the Key.
  225. --*/
  226. {
  227. #undef DEBSUB
  228. #define DEBSUB "PmHashFunction:"
  229. DWORD key; // hashed key value to be returned
  230. PULONGLONG p; // hash the key to PULONGLONG
  231. p = (PULONGLONG)Qkey;
  232. key = (DWORD)*p;
  233. return (key);
  234. }
  235. ULONG
  236. PmSearchTable (
  237. IN PQHASH_TABLE Table,
  238. IN PQHASH_ENTRY BeforeNode,
  239. IN PQHASH_ENTRY TargetNode,
  240. IN OUT PVOID Context
  241. )
  242. /*++
  243. Routine Description:
  244. This routine is called by the QHashEnumerateTable function and is used
  245. to add context to the enumeration. Here, we go through the table till
  246. a node containing a specified instance (name contained in the context structure)
  247. is reached.
  248. Arguments:
  249. Table - The hash table to be searched.
  250. BeforeNode - The node previous to the target node in the hash table(unused).
  251. AfterNode - The node which is being examined.
  252. Context - A structure containing the name to be matched and key value to be set.
  253. Return Value:
  254. FrsErrorFoundKey - Key mapping the name was found
  255. FrsErrorSuccess - Key was not found
  256. --*/
  257. {
  258. #undef DEBSUB
  259. #define DEBSUB "PmSearchTable:"
  260. PContextData contxt;
  261. PWCHAR InstanceName;
  262. PHT_REPLICA_SET_DATA p;
  263. PHT_REPLICA_CONN_DATA q;
  264. //
  265. // The context is of the type pointer to ContextData datastructure
  266. //
  267. contxt = (PContextData) Context;
  268. InstanceName = (PWCHAR) contxt->name;
  269. DPRINT1(5, "PERFMON: InstanceName: %ws\n", InstanceName);
  270. DPRINT1(5, "PERFMON: TargetNode: %08x\n", TargetNode);
  271. DPRINT1(5, "PERFMON: TargetNode->qDATA: %08X %08x\n",
  272. PRINTQUAD(TargetNode->QData));
  273. //
  274. // The Object Type is either REPLICASET or REPLICACONN
  275. //
  276. if (contxt->OBJType == REPLICASET) {
  277. //
  278. // Its a REPLICASET Object
  279. //
  280. p = (PHT_REPLICA_SET_DATA)(TargetNode->QData);
  281. DPRINT1(5, "PERFMON: p: %08x\n", p);
  282. DPRINT1(5, "PERFMON: p->oid: %08x\n", p->oid);
  283. DPRINT1(5, "PERFMON: p->oid->name: %08x\n", p->oid->name);
  284. DPRINT1(5, "PERFMON: p->oid->name: %ws\n", p->oid->name);
  285. DPRINT1(5, "PERFMON: p->oid->key: %08x %08x\n", PRINTQUAD(p->oid->key));
  286. //
  287. // Check to see if the names are the same
  288. //
  289. if ( (wcscmp(InstanceName, p->oid->name)) == 0) {
  290. //
  291. // Check to see if the names are the same
  292. //
  293. contxt->KeyValue = p->oid->key;
  294. DPRINT(5, "PERFMON: FOUND\n");
  295. return FrsErrorFoundKey;
  296. }
  297. else
  298. return FrsErrorSuccess; // Continue enumerating through the list of nodes
  299. }
  300. else {
  301. //
  302. // Its a REPLICACONN Object.
  303. //
  304. q = (PHT_REPLICA_CONN_DATA)(TargetNode->QData);
  305. DPRINT1(5, "PERFMON: q: %08x\n", q);
  306. DPRINT1(5, "PERFMON: q->oid: %08x\n", q->oid);
  307. DPRINT1(5, "PERFMON: q->oid->name: %08x\n", q->oid->name);
  308. DPRINT1(5, "PERFMON: q->oid->name: %ws\n", q->oid->name);
  309. DPRINT1(5, "PERFMON: q->oid->key: %08x %08x\n", PRINTQUAD(q->oid->key));
  310. if ( (wcscmp(InstanceName, q->oid->name)) == 0) {
  311. contxt->KeyValue = q->oid->key;
  312. DPRINT(5, "PERFMON: FOUND\n");
  313. return FrsErrorFoundKey;
  314. }
  315. else
  316. return FrsErrorSuccess;
  317. }
  318. }
  319. LONG
  320. PmInitPerfmonRegistryKeys (
  321. VOID
  322. )
  323. /*++
  324. Routine Description:
  325. This routine is the called by the ntfrs application to Initialize the
  326. appropriate Keys and Values of the PERFMON Objects in the Registry.
  327. It calls the PmInitializeRegistry routine (described below) on the Objects.
  328. It also adds the total instance to the REPLICASET Object.
  329. Arguments:
  330. none
  331. Return Value:
  332. ERROR_SUCCESS - The Initialization was successful OR
  333. Appropriate DWORD value for the Error status
  334. --*/
  335. {
  336. #undef DEBSUB
  337. #define DEBSUB "PmInitPerfmonRegistryKeys:"
  338. LONG WStatus = ERROR_SUCCESS;
  339. enum object ObjType;
  340. //
  341. // Initialize the REPLICASET Object
  342. //
  343. ObjType = REPLICASET;
  344. WStatus = PmInitializeRegistry(ObjType);
  345. if (!WIN_SUCCESS(WStatus)) {
  346. DPRINT(0, "Error: PmInitializeRegistry(L\"FileReplicaSet\")\n");
  347. return WStatus;
  348. }
  349. //
  350. // Initialize the REPLICACONN Object
  351. //
  352. ObjType = REPLICACONN;
  353. WStatus = PmInitializeRegistry(ObjType);
  354. if (!WIN_SUCCESS(WStatus)) {
  355. DPRINT(0, "Error: PmInitializeRegistry(L\"FileReplicaConn\")\n");
  356. return WStatus;
  357. }
  358. //
  359. // Set the fields of the total instance
  360. //
  361. PMTotalInst = (PHT_REPLICA_SET_DATA) FrsAlloc (sizeof(HT_REPLICA_SET_DATA));
  362. PMTotalInst->RepBackPtr = NULL;
  363. //
  364. // Add it to the REPLICASET Hash table
  365. //
  366. WStatus = AddPerfmonInstance(REPLICASET, PMTotalInst, TOTAL_NAME);
  367. return WStatus;
  368. }
  369. LONG
  370. PmInitializeRegistry (
  371. IN DWORD ObjectType
  372. )
  373. /*++
  374. Routine Description:
  375. This routine is the called by the PmInitPerfmonRegistryKeys function
  376. to Initialize the appropriate Keys and Values of the Object (ObjectType)
  377. in the Registry.
  378. Arguments:
  379. ObjectType - The Object whose Keys and Values have to be Initialized
  380. Return Value:
  381. ERROR_SUCCESS - The Initialization of the Object was successful OR
  382. Appropriate DWORD value for the Error status
  383. --*/
  384. {
  385. #undef DEBSUB
  386. #define DEBSUB "PmInitializeRegistry:"
  387. ULONG WStatus = ERROR_SUCCESS;
  388. ULONG WStatus1;
  389. DWORD size, flag;
  390. HKEY key = INVALID_HANDLE_VALUE;
  391. PWCHAR ObjSubKey, PerfSubKey, LinSubKey, OpFn, ClFn, CollFn, iniflCmd, iniflApp, unldCmd, unldApp;
  392. WCHAR CommandLine[MAX_CMD_LINE];
  393. DWORD type;
  394. DWORD CounterVersion = 0;
  395. DWORD Temp;
  396. BOOL UnloadCounters = FALSE;
  397. BOOL LoadCounters = FALSE;
  398. //
  399. // Set all the parameters used in the function depending upon the Type of Object
  400. //
  401. if ( ObjectType == REPLICASET ) {
  402. //
  403. // The Keys to be set in the registry
  404. //
  405. ObjSubKey = REPSETOBJSUBKEY;
  406. PerfSubKey = REPSETPERFSUBKEY;
  407. LinSubKey = REPSETLINSUBKEY;
  408. //
  409. // The Open function (called by PERFMON when it starts up) of REPLICASET
  410. //
  411. OpFn = REPSETOPENFN;
  412. //
  413. // The Close function (called by PERFMON when it closes) of REPLICASET
  414. //
  415. ClFn = REPSETCLOSEFN;
  416. //
  417. // The Collect function (called by PERFMON to collect data) of REPLICASET
  418. //
  419. CollFn = REPSETCOLLECTFN;
  420. //
  421. // The lodctr utility to add the counter values
  422. //
  423. iniflApp = LDCTRAPP;
  424. iniflCmd = REPSETINI;
  425. //
  426. // The unlodctr utility to remove the counter values
  427. //
  428. unldApp = UNLDCTRAPP;
  429. unldCmd = REPSETUNLD;
  430. } else {
  431. //
  432. // Similar settings for the REPLICACONN Object
  433. //
  434. ObjSubKey = REPCONNOBJSUBKEY;
  435. PerfSubKey = REPCONNPERFSUBKEY;
  436. LinSubKey = REPCONNLINSUBKEY;
  437. OpFn = REPCONNOPENFN;
  438. ClFn = REPCONNCLOSEFN;
  439. CollFn = REPCONNCOLLECTFN;
  440. iniflApp = LDCTRAPP;
  441. iniflCmd = REPCONNINI;
  442. unldApp = UNLDCTRAPP;
  443. unldCmd = REPCONNUNLD;
  444. }
  445. //
  446. // Create a key for the Object under the Sevices Key in the Registry. If the Key
  447. // already exists, its opened.
  448. //
  449. WStatus = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
  450. ObjSubKey,
  451. 0L,
  452. NULL,
  453. REG_OPTION_NON_VOLATILE,
  454. KEY_ALL_ACCESS,
  455. NULL,
  456. &key,
  457. &flag);
  458. CLEANUP_WS(0, "Error: RegCreateKeyEx.", WStatus, CLEANUP2);
  459. size = sizeof(DWORD);
  460. WStatus = RegQueryValueEx(key, L"Counter Version", NULL, &type, (PUCHAR)&CounterVersion, &size);
  461. if (!WIN_SUCCESS(WStatus) || (type != REG_DWORD) ||
  462. CounterVersion != NtFrsPerfCounterVer) {
  463. UnloadCounters = TRUE;
  464. LoadCounters = TRUE;
  465. }
  466. FRS_REG_CLOSE(key);
  467. //
  468. // Create a key called Performance under the Object's Key (created above) in the Registry
  469. //
  470. WStatus = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
  471. PerfSubKey,
  472. 0L,
  473. NULL,
  474. REG_OPTION_NON_VOLATILE,
  475. KEY_ALL_ACCESS,
  476. NULL,
  477. &key,
  478. &flag);
  479. CLEANUP_WS(0, "Error: RegCreateKeyEx.", WStatus, CLEANUP2);
  480. //
  481. // If its a newly created Performance key, we need to set some Values to it.
  482. // If it is a newly created performance key then we need to load the counters.
  483. //
  484. if (flag == REG_CREATED_NEW_KEY) {
  485. size = ((1 + wcslen(PERFDLLDIRECTORY)) * (sizeof(WCHAR)));
  486. WStatus = RegSetValueEx (key, L"Library", 0L, REG_EXPAND_SZ,
  487. (BYTE *)PERFDLLDIRECTORY, size);
  488. CLEANUP_WS(0, "Error: RegSetValueEx.", WStatus, CLEANUP);
  489. size = (1 + wcslen(OpFn)) * (sizeof(WCHAR));
  490. WStatus = RegSetValueEx (key, L"Open", 0L, REG_SZ, (BYTE *)OpFn, size);
  491. CLEANUP_WS(0, "Error: RegSetValueEx.", WStatus, CLEANUP);
  492. size = (1 + wcslen(ClFn)) * (sizeof(WCHAR));
  493. WStatus = RegSetValueEx (key, L"Close", 0L, REG_SZ, (BYTE *)ClFn, size);
  494. CLEANUP_WS(0, "Error: RegSetValueEx.", WStatus, CLEANUP);
  495. size = (1 + wcslen(CollFn)) * (sizeof(WCHAR));
  496. WStatus = RegSetValueEx (key, L"Collect", 0L, REG_SZ, (BYTE *)CollFn, size);
  497. CLEANUP_WS(0, "Error: RegSetValueEx.", WStatus, CLEANUP);
  498. //
  499. // The performance subkey is newly created. We only need
  500. // to load counters as they are new.
  501. //
  502. UnloadCounters = FALSE;
  503. LoadCounters = TRUE;
  504. } else {
  505. //
  506. // The performance key exists. If this key exists then
  507. // the counters are probably loaded. If someone has
  508. // manually unloaded the counters by calling unloadctr from
  509. // command line then the counters may be unloaded.
  510. // Look for the FirstCounter/FirstHelp/LastCounter/LastHelp
  511. // values. If they don't exist then the counters are not
  512. // loaded. Mark them to be loaded.
  513. //
  514. size = sizeof(DWORD);
  515. WStatus = RegQueryValueEx(key, L"First Counter", NULL, &type, (PUCHAR)&Temp, &size);
  516. if (!WIN_SUCCESS(WStatus) || (type != REG_DWORD)){
  517. // counters are not loaded.
  518. LoadCounters = TRUE;
  519. }
  520. }
  521. FRS_REG_CLOSE(key);
  522. if (UnloadCounters == TRUE) {
  523. //
  524. // Run unlodctr command on the application incase counters have changed
  525. // Copy the command line because CreateProcess() wants to be able to
  526. // write into it. Sigh.
  527. //
  528. wcscpy(CommandLine, unldCmd);
  529. DPRINT1(1,"Running: %ws\n", CommandLine);
  530. WStatus = FrsRunProcess(unldApp,
  531. CommandLine,
  532. INVALID_HANDLE_VALUE,
  533. INVALID_HANDLE_VALUE,
  534. INVALID_HANDLE_VALUE);
  535. //
  536. // If the unloadctr above failed then don't execute loadctr.
  537. // This avoids the registry from getting corrupted.
  538. //
  539. DPRINT1_WS(0, "Error Running %ws;", CommandLine, WStatus);
  540. }
  541. if (LoadCounters == TRUE ) {
  542. //
  543. // Run the lodctr command on the .ini file of the Object
  544. // Copy the command line because CreateProcess() wants to be able to
  545. // write into it. Sigh.
  546. //
  547. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ObjSubKey, 0, KEY_ALL_ACCESS, &key);
  548. CLEANUP_WS(0, "Error: RegOpenKeyEx.", WStatus, CLEANUP2);
  549. wcscpy(CommandLine, iniflCmd);
  550. DPRINT1(1,"Running: %ws\n", CommandLine);
  551. WStatus = FrsRunProcess(iniflApp,
  552. CommandLine,
  553. INVALID_HANDLE_VALUE,
  554. INVALID_HANDLE_VALUE,
  555. INVALID_HANDLE_VALUE);
  556. if (!WIN_SUCCESS(WStatus)) {
  557. //
  558. // If there was an error loading the counters then set
  559. // the "Counter Version" value to 0 so we try to
  560. // load the counters the next time.
  561. //
  562. CounterVersion = 0;
  563. WStatus = RegSetValueEx(key, L"Counter Version", 0, REG_DWORD, (PCHAR)&CounterVersion, sizeof(DWORD));
  564. CLEANUP_WS(0, "Error: RegSetValueEx.", WStatus, CLEANUP);
  565. DPRINT1_WS(0, "Error Running %ws;", CommandLine, WStatus);
  566. goto CLEANUP;
  567. }
  568. //
  569. // If the counters are loaded correctly then update the
  570. // "Counter Version" so we don't load them again next
  571. // time.
  572. //
  573. WStatus = RegSetValueEx(key, L"Counter Version", 0, REG_DWORD, (PCHAR)&NtFrsPerfCounterVer, sizeof(DWORD));
  574. CLEANUP_WS(0, "Error: RegSetValueEx.", WStatus, CLEANUP);
  575. FRS_REG_CLOSE(key);
  576. }
  577. //
  578. // Create a key called Linkage under the Object's Key (created above) in the Registry
  579. //
  580. WStatus = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
  581. LinSubKey,
  582. 0L,
  583. NULL,
  584. REG_OPTION_NON_VOLATILE,
  585. KEY_ALL_ACCESS,
  586. NULL,
  587. &key,
  588. &flag);
  589. CLEANUP_WS(0, "Error: RegCreateKeyEx. (LINKAGE)", WStatus, CLEANUP2);
  590. //
  591. // Create the Export Value (for instances of Objects) under Linkage
  592. // Its set to NULL when the ntfrs applicationis started and the
  593. // Instances are added as they get created by the application
  594. //
  595. WStatus = RegSetValueEx (key, L"Export", 0L, REG_MULTI_SZ, NULL, 0);
  596. CLEANUP_WS(0, "Error: RegSetValueEx Export.", WStatus, CLEANUP);
  597. CLEANUP:
  598. FRS_REG_CLOSE(key);
  599. CLEANUP2:
  600. //
  601. // If the Initialization was successful, return ERROR_SUCCESS
  602. //
  603. return WStatus;
  604. }
  605. ULONG
  606. AddPerfmonInstance (
  607. IN DWORD ObjectType,
  608. IN PVOID addr,
  609. IN PWCHAR InstanceName
  610. )
  611. /*++
  612. Routine Description:
  613. This routine is called by the ntfrs application to add an Instance of
  614. a particular Object Type to the Registry and the Hash Table.
  615. Arguments:
  616. ObjectType - The Object whose instance has to be added
  617. addr - The data structure for the Instance Counters stored in Hash Table
  618. InstanceName - The instance name of the object.
  619. Return Value:
  620. ERROR_SUCCESS - The Initialization of the Object was successful OR
  621. Appropriate DWORD value for the Error status
  622. --*/
  623. {
  624. #undef DEBSUB
  625. #define DEBSUB "AddPerfmonInstance:"
  626. BOOL flag = TRUE;
  627. BOOL HaveKey = FALSE;
  628. ULONG WStatus = ERROR_SUCCESS;
  629. ULONG WStatus1;
  630. ULONG GStatus;
  631. DWORD Type, size, len, totallen;
  632. HKEY key = INVALID_HANDLE_VALUE;
  633. PWCHAR SubKey, p, r, s;
  634. PWCHAR NewExport = NULL;
  635. PWCHAR ValueData = NULL;
  636. PHT_REPLICA_SET_DATA rsdata;
  637. PHT_REPLICA_CONN_DATA rcdata;
  638. PQHASH_TABLE HashTable;
  639. PULONGLONG QKey;
  640. PULONGLONG QData;
  641. PPERFMON_OBJECT_ID PmOid;
  642. //
  643. // Addition must be mutually exclusive
  644. // Check is its safe to enter before going ahead
  645. //
  646. if (!HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
  647. return ERROR_SUCCESS;
  648. }
  649. //
  650. // Alloc the perfmon object ID struct and the space for the instance name.
  651. //
  652. PmOid = (PPERFMON_OBJECT_ID) FrsAlloc (sizeof(PERFMON_OBJECT_ID));
  653. PmOid->name = FrsAlloc((wcslen(InstanceName)+1) * sizeof(WCHAR));
  654. wcscpy(PmOid->name, InstanceName);
  655. AcquirePerfmonLock;
  656. //
  657. // set up params based on object type. Alloc storage for OID and name.
  658. //
  659. if ( ObjectType == REPLICASET ) {
  660. //
  661. // L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaSet\\Linkage"
  662. //
  663. SubKey = REPSETLINSUBKEY;
  664. rsdata = (PHT_REPLICA_SET_DATA) addr;
  665. if (rsdata->oid != NULL) {
  666. WStatus = ERROR_INVALID_PARAMETER;
  667. goto CLEANUP;
  668. }
  669. rsdata->oid = PmOid;
  670. HashTable = HTReplicaSet;
  671. QKey = &(rsdata->oid->key);
  672. QData = (PULONGLONG)&(rsdata);
  673. } else {
  674. //
  675. // L"SYSTEM\\CurrentControlSet\\Services\\FileReplicaConn\\Linkage"
  676. //
  677. SubKey = REPCONNLINSUBKEY;
  678. rcdata = (PHT_REPLICA_CONN_DATA) addr;
  679. if (rcdata->oid != NULL) {
  680. WStatus = ERROR_INVALID_PARAMETER;
  681. goto CLEANUP;
  682. }
  683. rcdata->oid = PmOid;
  684. HashTable = HTReplicaConn;
  685. QKey = &(rcdata->oid->key);
  686. QData = (PULONGLONG)&(rcdata);
  687. }
  688. //
  689. // Open the Linkge Key of the Objevt which contains the Export Value
  690. //
  691. WStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE, SubKey, 0L, KEY_ALL_ACCESS, &key);
  692. CLEANUP1_WS(0, "Error: RegOpenKeyEx (%ws).", SubKey, WStatus, CLEANUP);
  693. HaveKey = TRUE;
  694. //
  695. // Fetch the Export value
  696. //
  697. WStatus = RegQueryValueEx(key, L"Export", NULL, &Type, NULL, &size);
  698. CLEANUP_WS(0, "RegQueryValueEx(Export);", WStatus, CLEANUP);
  699. if (Type != REG_MULTI_SZ) {
  700. DPRINT2(0, "RegQueryValueEx(Export) is Type %d; not Type %d\n",
  701. Type, REG_MULTI_SZ);
  702. WStatus = ERROR_NO_TOKEN;
  703. goto CLEANUP;
  704. }
  705. //
  706. // Need to check if size == 0 as FrsAlloc asserts if called with 0 as the
  707. // first parameter (prefix fix).
  708. //
  709. ValueData = (size == 0) ? NULL : (PWCHAR) FrsAlloc (size);
  710. WStatus = RegQueryValueEx(key, L"Export", NULL, &Type, (PUCHAR)ValueData, &size);
  711. CLEANUP_WS(0, "RegQueryValueEx(Export);", WStatus, CLEANUP);
  712. if (Type != REG_MULTI_SZ) {
  713. DPRINT2(0, "RegQueryValueEx(Export) is Type %d; not Type %d\n",
  714. Type, REG_MULTI_SZ);
  715. WStatus = ERROR_NO_TOKEN;
  716. goto CLEANUP;
  717. }
  718. DPRINT1(4, "Export was = %ws\n", ValueData);
  719. if (size > sizeof(WCHAR)) {
  720. len = (1 + wcslen(InstanceName)) * sizeof(WCHAR);
  721. totallen = size + len;
  722. p = (PWCHAR) FrsAlloc (totallen);
  723. NewExport = p;
  724. r = ValueData;
  725. while (TRUE) {
  726. if ( (wcscmp(r, InstanceName)) == 0 ) {
  727. //
  728. // The Instance Value already exists
  729. //
  730. flag = FALSE;
  731. break;
  732. }
  733. wcscpy(p, r);
  734. p = wcschr(p, L'\0');
  735. r = wcschr(r, L'\0');
  736. p = p + 1;
  737. r = r + 1;
  738. if ( *r == L'\0') {
  739. break;
  740. }
  741. }
  742. if (flag) {
  743. wcscpy(p, InstanceName);
  744. p = wcschr(p, L'\0');
  745. *(p+1) = L'\0';
  746. //
  747. // If its a new Instance add it to the hash table
  748. //
  749. if ( ObjectType == REPLICASET ) {
  750. //
  751. // Set the ID of the Instance and increment for next.
  752. //
  753. rsdata->oid->key = FRS_UniqueID;
  754. FRS_UniqueID++;
  755. } else {
  756. //
  757. // Set the ID of the Instance and increment for next.
  758. //
  759. rcdata->oid->key = FRC_UniqueID;
  760. FRC_UniqueID++;
  761. }
  762. } else {
  763. //
  764. // This Instance already exists, so make no changes to the Export value
  765. //
  766. WStatus = ERROR_ALREADY_EXISTS;
  767. goto CLEANUP;
  768. }
  769. } else {
  770. //
  771. // This is the only Instance of the Object
  772. //
  773. len = (2 + wcslen(InstanceName)) * sizeof(WCHAR);
  774. NewExport = (PWCHAR) FrsAlloc (len);
  775. wcscpy(NewExport, InstanceName);
  776. p = wcschr(NewExport, L'\0');
  777. *(p+1) = L'\0';
  778. totallen = len;
  779. if ( ObjectType == REPLICASET ) {
  780. rsdata->oid->key = FRS_UniqueID;
  781. FRS_UniqueID++;
  782. } else {
  783. rcdata->oid->key = FRC_UniqueID;
  784. FRC_UniqueID++;
  785. }
  786. }
  787. DPRINT4(4, "PERFMON: Type: %d, Key: %08x %08x, QData: %08x %08x, Name: %ws\n",
  788. ObjectType, PRINTQUAD(*QKey), PRINTQUAD(*QData), InstanceName);
  789. GStatus = QHashInsert(HashTable, QKey, QData, 0, FALSE);
  790. if (GStatus != GHT_STATUS_SUCCESS) {
  791. DPRINT(0, "Error: QHashInsert Failed\n");
  792. WStatus = ERROR_ALREADY_EXISTS;
  793. goto CLEANUP;
  794. }
  795. //
  796. // Set the Export Value with the added instance (if any)
  797. //
  798. WStatus = RegSetValueEx (key, L"Export", 0L, REG_MULTI_SZ, (BYTE *)NewExport, totallen);
  799. CLEANUP_WS(0, "Error: RegSetValueEx (Export).", WStatus, CLEANUP);
  800. WStatus = ERROR_SUCCESS;
  801. CLEANUP:
  802. if (!WIN_SUCCESS(WStatus)) {
  803. DPRINT1_WS(0, "ERROR: Add instance failed for %ws :", InstanceName, WStatus);
  804. //
  805. // Failed to add the instance. Free the OID and name.
  806. //
  807. FrsFree(PmOid->name);
  808. if ( ObjectType == REPLICASET ) {
  809. rsdata->oid = FrsFree (PmOid);
  810. } else {
  811. rcdata->oid = FrsFree (PmOid);
  812. }
  813. }
  814. //
  815. // Free the malloced memory
  816. //
  817. ValueData = FrsFree (ValueData);
  818. NewExport = FrsFree (NewExport);
  819. if (HaveKey) {
  820. FRS_REG_CLOSE(key);
  821. }
  822. //
  823. // Its safe to leave the critical section now
  824. //
  825. ReleasePerfmonLock;
  826. return WStatus;
  827. }
  828. DWORD
  829. DeletePerfmonInstance(
  830. IN DWORD ObjectType,
  831. IN PVOID addr
  832. )
  833. /*++
  834. Routine Description:
  835. This routine is called by the ntfrs application to delete an Instance of a particular
  836. Object Type from the Registry and the Hash Table. It is very similar to the adding
  837. function described above.
  838. Arguments:
  839. ObjectType - The Object whose instance has to be added
  840. addr - The data structure for the Instance Counters stored in Hash Table
  841. Return Value:
  842. ERROR_SUCCESS - The Initialization of the Object was successful OR
  843. Appropriate DWORD value for the Error status
  844. --*/
  845. {
  846. #undef DEBSUB
  847. #define DEBSUB "DeletePerfmonInstance:"
  848. ULONGLONG QKey;
  849. ULONG WStatus = ERROR_SUCCESS;
  850. ULONG WStatus1;
  851. PQHASH_TABLE HashTable;
  852. ULONG GStatus;
  853. DWORD Type, size, len, TotalLen;
  854. HKEY key = INVALID_HANDLE_VALUE;
  855. PWCHAR SubKey, p, r, s, InstanceName;
  856. PWCHAR ValueData = NULL;
  857. PWCHAR q = NULL;
  858. PHT_REPLICA_SET_DATA rsdata;
  859. PHT_REPLICA_CONN_DATA rcdata;
  860. if (addr == NULL) {
  861. return ERROR_SUCCESS;
  862. }
  863. //
  864. // Deletion must be mutually exclusive
  865. // Check is its safe to enter before going ahead
  866. //
  867. if (!HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
  868. return ERROR_SUCCESS;
  869. }
  870. if ( ObjectType == REPLICASET ) {
  871. //
  872. // Replica Set Object
  873. //
  874. SubKey = REPSETLINSUBKEY;
  875. rsdata = (HT_REPLICA_SET_DATA *) addr;
  876. if ((rsdata->oid == NULL) || (rsdata->oid->name == NULL)) {
  877. return ERROR_SUCCESS;
  878. }
  879. InstanceName = rsdata->oid->name;
  880. HashTable = HTReplicaSet;
  881. QKey = rsdata->oid->key;
  882. DPRINT1(4, "Replica Free - %ws\n", InstanceName);
  883. } else {
  884. //
  885. // Replica Connection Object.
  886. //
  887. SubKey = REPCONNLINSUBKEY;
  888. rcdata = (HT_REPLICA_CONN_DATA *) addr;
  889. if ((rcdata->oid == NULL) || (rcdata->oid->name == NULL)) {
  890. return ERROR_SUCCESS;
  891. }
  892. InstanceName = rcdata->oid->name;
  893. HashTable = HTReplicaConn;
  894. QKey = rcdata->oid->key;
  895. DPRINT1(4, "Cxtion Free - %ws\n", InstanceName);
  896. }
  897. AcquirePerfmonLock;
  898. //
  899. // Pull the Instance key from the hash table.
  900. //
  901. DPRINT1(4, "QKey: %08x %08x\n", PRINTQUAD(QKey));
  902. if (QKey != QUADZERO ) {
  903. GStatus = QHashDelete(HashTable, &QKey);
  904. if (GStatus != GHT_STATUS_SUCCESS) {
  905. DPRINT1(0, "Error: QHashDelete. GStatus = %d\n", GStatus);
  906. }
  907. }
  908. WStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE, SubKey, 0L, KEY_ALL_ACCESS, &key);
  909. CLEANUP1_WS(0, "RegOpenKeyEx(%ws);", SubKey, WStatus, CLEANUP_UNLOCK);
  910. //
  911. // Fetch the Export value
  912. //
  913. WStatus = RegQueryValueEx(key, L"Export", NULL, &Type, NULL, &size);
  914. CLEANUP_WS(0, "RegQueryValueEx(Export);", WStatus, CLEANUP);
  915. if (Type != REG_MULTI_SZ) {
  916. DPRINT2(0, "RegQueryValueEx(Export) is Type %d; not Type %d\n",
  917. Type, REG_MULTI_SZ);
  918. WStatus = ERROR_NO_TOKEN;
  919. goto CLEANUP;
  920. }
  921. len = (1 + wcslen(InstanceName)) * sizeof(WCHAR);
  922. if (size < len) {
  923. WStatus = ERROR_INVALID_PARAMETER;
  924. goto CLEANUP;
  925. }
  926. TotalLen = (size - len);
  927. //
  928. // Need to check if size == 0 as FrsAlloc asserts if called with 0 as the first parameter (prefix fix).
  929. //
  930. ValueData = (size == 0) ? NULL : (PWCHAR) FrsAlloc (size);
  931. WStatus = RegQueryValueEx(key, L"Export", NULL, &Type, (PUCHAR)ValueData, &size);
  932. CLEANUP_WS(0, "RegQueryValueEx(Export);", WStatus, CLEANUP);
  933. if (Type != REG_MULTI_SZ) {
  934. DPRINT2(0, "RegQueryValueEx(Export) is Type %d; not Type %d\n",
  935. Type, REG_MULTI_SZ);
  936. WStatus = ERROR_NO_TOKEN;
  937. goto CLEANUP;
  938. }
  939. DPRINT1(4, "Export was = %ws\n", ValueData);
  940. // Note: Perf: fix the below to do an inplace delete of the instance strimg.
  941. //
  942. // For REG_MULTI_SZ there are two UNICODE_NULLs at the end, one is accounted
  943. // for above.
  944. //
  945. if (TotalLen > sizeof(WCHAR)) {
  946. p = (PWCHAR) FrsAlloc (TotalLen);
  947. q = p;
  948. r = ValueData;
  949. while (TRUE) {
  950. if ( (wcscmp(r, InstanceName)) == 0) {
  951. r = wcschr(r, L'\0');
  952. r = r + 1;
  953. if (*r == L'\0')
  954. break;
  955. else
  956. continue;
  957. }
  958. wcscpy(p, r);
  959. p = wcschr(p, L'\0');
  960. r = wcschr(r, L'\0');
  961. p = p + 1;
  962. r = r + 1;
  963. if (*r == L'\0') {
  964. *p = L'\0';
  965. break;
  966. }
  967. }
  968. }
  969. else {
  970. q = NULL;
  971. TotalLen = 0;
  972. }
  973. DPRINT1(4, "Export now = %ws\n", q);
  974. //
  975. // Set the Export Value to the Updated Instance List
  976. //
  977. WStatus = RegSetValueEx (key, L"Export", 0L, REG_MULTI_SZ, (BYTE *)q, TotalLen);
  978. CLEANUP_WS(0, "RegSetValueEx(Export);", WStatus, CLEANUP);
  979. CLEANUP:
  980. //
  981. // Free up the malloced memory
  982. //
  983. FrsFree (ValueData);
  984. FrsFree (q);
  985. FRS_REG_CLOSE(key);
  986. //
  987. // Free the name and oid struct so this func is not called again when the
  988. // replica set or connection struct is finally freed.
  989. //
  990. if ( ObjectType == REPLICASET ) {
  991. rsdata->oid->name = FrsFree(rsdata->oid->name);
  992. rsdata->oid = FrsFree(rsdata->oid);
  993. } else {
  994. rcdata->oid->name = FrsFree(rcdata->oid->name);
  995. rcdata->oid = FrsFree(rcdata->oid);
  996. }
  997. CLEANUP_UNLOCK:
  998. //
  999. // Its safe to leave the critical section now
  1000. //
  1001. ReleasePerfmonLock;
  1002. return WStatus;
  1003. }
  1004. ULONGLONG
  1005. PmFindTheKeyValue (
  1006. IN PContextData Context
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. This routine is called by the RPC server function GetIndicesOfInstancesFromServer, to
  1011. get the index value of an Instance.
  1012. Arguments:
  1013. Context - The structure containing the name of the Instance whose Key
  1014. value has to be determined.
  1015. Return Value:
  1016. The Key for the Instance or INVALIDKEY if the Instance was not
  1017. found in the Hash Table
  1018. --*/
  1019. {
  1020. #undef DEBSUB
  1021. #define DEBSUB "PmFindTheKeyValue:"
  1022. ULONGLONG QKeyValue = (ULONGLONG)INVALIDKEY;
  1023. DWORD ret;
  1024. PQHASH_TABLE HashTable;
  1025. if (!HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
  1026. return (ULONGLONG)INVALIDKEY;
  1027. }
  1028. HashTable = (Context->OBJType == REPLICASET) ? HTReplicaSet : HTReplicaConn;
  1029. try {
  1030. //
  1031. // Deletion must be mutually exclusive
  1032. // Check is its safe to enter before going ahead
  1033. //
  1034. AcquirePerfmonLock;
  1035. //
  1036. // Enumerate through the Hash Table and if a matching Instance
  1037. // name is found, return its Key value
  1038. //
  1039. ret = QHashEnumerateTable(HashTable, PmSearchTable, Context);
  1040. if ( ret == FrsErrorFoundKey) {
  1041. QKeyValue = Context->KeyValue;
  1042. }
  1043. } finally {
  1044. ReleasePerfmonLock;
  1045. }
  1046. return QKeyValue;
  1047. }
  1048. //
  1049. // The function is implemented in frsrpc.c
  1050. //
  1051. DWORD
  1052. FrsRpcAccessChecks(
  1053. IN HANDLE ServerHandle,
  1054. IN DWORD RpcApiIndex
  1055. );
  1056. DWORD
  1057. GetIndicesOfInstancesFromServer (
  1058. IN handle_t Handle,
  1059. IN OUT OpenRpcData *packt
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. This is an RPC server routine that is called by the client (Performance DLL
  1064. for the FileReplicaSet and FileRepicaConn Objects of PERFMON) to set the
  1065. indices for Instance names
  1066. Arguments:
  1067. Handle - The RPC binding handle
  1068. packt - The structure (sent by the client) containing the Instance Names
  1069. whose indices have to be set and passed back to the client
  1070. Return Value:
  1071. none
  1072. --*/
  1073. {
  1074. #undef DEBSUB
  1075. #define DEBSUB "GetIndicesOfInstancesFromServer:"
  1076. LONG i;
  1077. ContextData context;
  1078. ULONG WStatus;
  1079. LONG NumInstanceNames;
  1080. WStatus = FrsRpcAccessChecks(Handle, ACX_COLLECT_PERFMON_DATA);
  1081. CLEANUP_WS(4, "Collect Perfmon Data Access check failed.", WStatus, CLEANUP);
  1082. //
  1083. // Its possible that the RPC end points of PERFMON get initialized before
  1084. // the InitializePerfmonServer gets called. If this RPC call has been made
  1085. // before initialization, return error so that the Open function gets called
  1086. // again by the perflib dll.
  1087. //
  1088. if (PMTotalInst == NULL) {
  1089. WStatus = ERROR_INVALID_DATA;
  1090. }
  1091. CLEANUP_WS(4, "Perfmon server uninitialized. Can't return data.", WStatus, CLEANUP);
  1092. try {
  1093. if ((packt == NULL) || (packt->ver == NULL)) {
  1094. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1095. return ERROR_INVALID_PARAMETER;
  1096. }
  1097. //
  1098. // Set the version to zero(its unused)
  1099. //
  1100. *(packt->ver) = 0;
  1101. //
  1102. // Set the appropriate Object Type
  1103. //
  1104. if (packt->ObjectType == REPSET) {
  1105. context.OBJType = REPLICASET;
  1106. }
  1107. else
  1108. if (packt->ObjectType == REPCONN) {
  1109. context.OBJType = REPLICACONN;
  1110. } else {
  1111. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1112. return ERROR_INVALID_PARAMETER;
  1113. }
  1114. //
  1115. // Check valid parameters.
  1116. //
  1117. if ((packt->instnames == NULL) ||
  1118. (packt->indices == NULL) ||
  1119. (packt->numofinst > packt->instnames->size) ||
  1120. (packt->numofinst > packt->indices->size)) {
  1121. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1122. return ERROR_INVALID_PARAMETER;
  1123. }
  1124. NumInstanceNames = packt->numofinst;
  1125. for (i = 0; i < NumInstanceNames; i++) {
  1126. context.name = packt->instnames->InstanceNames[i].name;
  1127. if ((context.name == NULL) ||
  1128. (wcslen(context.name) > PERFMON_MAX_INSTANCE_LENGTH)) {
  1129. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1130. return ERROR_INVALID_PARAMETER;
  1131. }
  1132. DPRINT2(4, "The instance name of instance %d is %ws\n", i+1, context.name);
  1133. //
  1134. // Set the Index for the Instance name
  1135. //
  1136. packt->indices->index[i] = (DWORD) PmFindTheKeyValue (&context);
  1137. DPRINT2(4, "The instance index of instance %ws is %d\n",
  1138. context.name, packt->indices->index[i]);
  1139. }
  1140. } except (EXCEPTION_EXECUTE_HANDLER) {
  1141. //
  1142. // Exception
  1143. //
  1144. GET_EXCEPTION_CODE(WStatus);
  1145. }
  1146. CLEANUP:
  1147. return WStatus;
  1148. }
  1149. DWORD
  1150. GetCounterDataOfInstancesFromServer(
  1151. IN handle_t Handle,
  1152. IN OUT CollectRpcData *packg
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. This is an RPC server routine that is called by the client (Performance DLL
  1157. for the FileReplicaSet and FileRepicaConn Objects of PERFMON) to collect
  1158. data for the Instance counters.
  1159. Arguments:
  1160. Handle - The RPC binding handle
  1161. packg - The structure (sent by the client) containing the indices of
  1162. instances whose counters data has to be sent back to the client.
  1163. Return Value:
  1164. none
  1165. --*/
  1166. {
  1167. #undef DEBSUB
  1168. #define DEBSUB "GetCounterDataOfInstancesFromServer:"
  1169. ULONGLONG InstanceId;
  1170. ULONGLONG CData;
  1171. ULONG WStatus = ERROR_SUCCESS;
  1172. LONG i, j;
  1173. DWORD GStatus;
  1174. ULONG_PTR Flags;
  1175. BOOL FirstPass;
  1176. PBYTE vd;
  1177. PHT_REPLICA_SET_DATA rsdat;
  1178. PHT_REPLICA_CONN_DATA rcdat;
  1179. ULONG COffset, CSize, DataSize;
  1180. LONG NumInstances;
  1181. PQHASH_TABLE HashTable;
  1182. PWCHAR OurName;
  1183. PReplicaSetCounters Total, Rsi;
  1184. //
  1185. // Make security check on callers access to perfmon data.
  1186. //
  1187. WStatus = FrsRpcAccessChecks(Handle, ACX_COLLECT_PERFMON_DATA);
  1188. CLEANUP_WS(4, "Collect Perfmon Data Access check failed.", WStatus, CLEANUP);
  1189. //
  1190. // Its possible that the RPC end points of PERFMON get initialized before
  1191. // the InitializePerfmonServer gets called. This is possible if the service
  1192. // is stopped and restarted and PERFMON continued to run in between.
  1193. //
  1194. if (PMTotalInst == NULL) {
  1195. WStatus = ERROR_INVALID_DATA;
  1196. }
  1197. CLEANUP_WS(4, "Perfmon server uninitialized. Can't return data.", WStatus, CLEANUP);
  1198. try {
  1199. if (packg == NULL) {
  1200. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1201. return ERROR_INVALID_PARAMETER;
  1202. }
  1203. //
  1204. // Set the appropriate Object Type
  1205. //
  1206. if (packg->ObjectType == REPSET) {
  1207. DataSize = SIZEOF_REPSET_COUNTER_DATA;
  1208. HashTable = HTReplicaSet;
  1209. } else
  1210. if (packg->ObjectType == REPCONN) {
  1211. DataSize = SIZEOF_REPCONN_COUNTER_DATA;
  1212. HashTable = HTReplicaConn;
  1213. } else {
  1214. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1215. return ERROR_INVALID_PARAMETER;
  1216. }
  1217. //
  1218. // Check valid parameters.
  1219. //
  1220. if ((packg->databuff == NULL) ||
  1221. (packg->indices == NULL) ||
  1222. (packg->databuff->data == NULL) ||
  1223. (packg->numofinst > packg->indices->size)) {
  1224. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1225. return ERROR_INVALID_PARAMETER;
  1226. }
  1227. NumInstances = packg->numofinst;
  1228. //
  1229. // Set vd to the memory where counter data is to be filled
  1230. //
  1231. vd = packg->databuff->data;
  1232. DPRINT1(5, "PERFMON: packg->ObjectType: %d\n", packg->ObjectType);
  1233. DPRINT1(5, "PERFMON: packg->numofinst: %d\n", packg->numofinst);
  1234. DPRINT1(5, "PERFMON: packg->databuff->data: %d\n", vd);
  1235. DPRINT1(5, "PERFMON: packg->databuff->size: %d\n", packg->databuff->size);
  1236. if (packg->ObjectType == REPSET) {
  1237. //
  1238. // First accumulate the totals for the replica set object
  1239. //
  1240. FirstPass = TRUE;
  1241. Total = &PMTotalInst->FRSCounter;
  1242. for (i = 0; i < NumInstances; i++) {
  1243. if (packg->indices->index[i] == INVALIDKEY) {
  1244. //
  1245. // If the key is INVALID, data is zeros
  1246. //
  1247. DPRINT(5, "PERFMON: Invalid Key sent.\n");
  1248. continue;
  1249. }
  1250. //
  1251. // set the value of index to quadword InstanceId
  1252. //
  1253. InstanceId = (ULONGLONG)packg->indices->index[i];
  1254. //
  1255. // Lookup for the counter data for the index value of the Instance
  1256. //
  1257. GStatus = QHashLookup(HTReplicaSet, &InstanceId, &CData, &Flags);
  1258. if (GStatus != GHT_STATUS_SUCCESS) {
  1259. DPRINT(5, "PERFMON: Key not found.\n");
  1260. continue;
  1261. }
  1262. rsdat = (PHT_REPLICA_SET_DATA)(CData);
  1263. //
  1264. // Skip the total instance.
  1265. //
  1266. if (wcscmp(rsdat->oid->name, TOTAL_NAME) == 0) {
  1267. continue;
  1268. }
  1269. Rsi = &rsdat->FRSCounter;
  1270. //
  1271. // Accumulate the counters for this instance into the total.
  1272. //
  1273. for (j = 0; j < FRS_NUMOFCOUNTERS; j++) {
  1274. //
  1275. // If a count is Service Wide then leave the Total alone.
  1276. //
  1277. if (BooleanFlagOn(RepSetInitData[j].Flags, PM_RS_FLAG_SVC_WIDE)) {
  1278. continue;
  1279. }
  1280. COffset = RepSetInitData[j].offset;
  1281. CSize = RepSetInitData[j].size;
  1282. if (CSize == sizeof(ULONG)) {
  1283. if (FirstPass) {
  1284. *(PULONG)((PCHAR) Total + COffset) = (ULONG) 0;
  1285. }
  1286. *(PULONG)((PCHAR) Total + COffset) +=
  1287. *(PULONG)((PCHAR) Rsi + COffset);
  1288. } else
  1289. if (CSize == sizeof(ULONGLONG)) {
  1290. if (FirstPass) {
  1291. *(PULONGLONG)((PCHAR) Total + COffset) = QUADZERO;
  1292. }
  1293. *(PULONGLONG)((PCHAR) Total + COffset) +=
  1294. *(PULONGLONG)((PCHAR) Rsi + COffset);
  1295. }
  1296. }
  1297. FirstPass = FALSE;
  1298. }
  1299. }
  1300. //
  1301. // Check if the buffer is large enough to send all the
  1302. // requested data.
  1303. //
  1304. if (packg->databuff->size < (LONG)(NumInstances*DataSize)) {
  1305. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1306. return ERROR_INVALID_PARAMETER;
  1307. }
  1308. //
  1309. // Now return the data to Perfmon.
  1310. //
  1311. for (i = 0; i < NumInstances; i++) {
  1312. //
  1313. // The amount of data returned should not exceed the buffer size
  1314. //
  1315. if ((vd - packg->databuff->data) > packg->databuff->size) {
  1316. DPRINT(4, "PERFMON: ERROR_INVALID_PARAMETER\n");
  1317. return ERROR_INVALID_PARAMETER;
  1318. }
  1319. if (packg->indices->index[i] == INVALIDKEY) {
  1320. //
  1321. // If the key is INVALID, data is zeros
  1322. //
  1323. DPRINT(5, "PERFMON: Invalid Key sent.\n");
  1324. ZeroMemory (vd, DataSize);
  1325. vd += DataSize;
  1326. continue;
  1327. }
  1328. //
  1329. // set the value of index to quadword InstanceId
  1330. //
  1331. InstanceId = (ULONGLONG)packg->indices->index[i];
  1332. //
  1333. // Lookup for the counter data for the index value of the Instance
  1334. //
  1335. GStatus = QHashLookup(HashTable, &InstanceId, &CData, &Flags);
  1336. if ( GStatus == GHT_STATUS_SUCCESS) {
  1337. if (packg->ObjectType == REPSET) {
  1338. //
  1339. // Return data for replica set
  1340. //
  1341. rsdat = (PHT_REPLICA_SET_DATA)(CData);
  1342. OurName = rsdat->oid->name;
  1343. //
  1344. // Set all the Change Order counters which are the sum of the
  1345. // ones already set.
  1346. //
  1347. PmSetTheCOCounters(rsdat);
  1348. CopyMemory (vd, &(rsdat->FRSCounter), DataSize);
  1349. } else {
  1350. //
  1351. // Return data for replica connection
  1352. //
  1353. rcdat = (PHT_REPLICA_CONN_DATA)(CData);
  1354. OurName = rcdat->oid->name;
  1355. CopyMemory (vd, &(rcdat->FRCCounter), DataSize);
  1356. }
  1357. DPRINT2(5, "%ws is the name associated with index %d\n",
  1358. OurName, packg->indices->index[i]);
  1359. } else {
  1360. //
  1361. // Instance not found, return zeros for counter data
  1362. //
  1363. DPRINT1(0, "The instance not found for index %d\n",
  1364. packg->indices->index[i]);
  1365. ZeroMemory (vd, DataSize);
  1366. }
  1367. //
  1368. // Increment vd by SIZEOF_REPSET_COUNTER_DATA
  1369. //
  1370. vd += DataSize;
  1371. }
  1372. } except (EXCEPTION_EXECUTE_HANDLER) {
  1373. //
  1374. // Exception
  1375. //
  1376. GET_EXCEPTION_CODE(WStatus);
  1377. }
  1378. CLEANUP:
  1379. return WStatus;
  1380. }
  1381. VOID
  1382. PmSetTheCOCounters(
  1383. PHT_REPLICA_SET_DATA RSData
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. This routine sets the Change Order countters which are the sums
  1388. of the counters already set in the ntfrs application
  1389. Arguments:
  1390. RSData - Pointer to the HT_REPLICA_SET_DATA structure whose counters
  1391. need to be set
  1392. Return Value:
  1393. none
  1394. --*/
  1395. {
  1396. #undef DEBSUB
  1397. #define DEBSUB "PmSetTheCOCounters:"
  1398. //
  1399. // Set the Local and Remote Retried Counter Values
  1400. //
  1401. RSData->FRSCounter.LCORetried = RSData->FRSCounter.LCORetriedGen +
  1402. RSData->FRSCounter.LCORetriedFet +
  1403. RSData->FRSCounter.LCORetriedIns +
  1404. RSData->FRSCounter.LCORetriedRen;
  1405. RSData->FRSCounter.RCORetried = RSData->FRSCounter.RCORetriedGen +
  1406. RSData->FRSCounter.RCORetriedFet +
  1407. RSData->FRSCounter.RCORetriedIns +
  1408. RSData->FRSCounter.RCORetriedRen;
  1409. //
  1410. // Set all the CO counter values
  1411. //
  1412. RSData->FRSCounter.COIssued = RSData->FRSCounter.LCOIssued +
  1413. RSData->FRSCounter.RCOIssued;
  1414. RSData->FRSCounter.CORetired = RSData->FRSCounter.LCORetired +
  1415. RSData->FRSCounter.RCORetired;
  1416. RSData->FRSCounter.COAborted = RSData->FRSCounter.LCOAborted +
  1417. RSData->FRSCounter.RCOAborted;
  1418. RSData->FRSCounter.CORetried = RSData->FRSCounter.LCORetried +
  1419. RSData->FRSCounter.RCORetried;
  1420. RSData->FRSCounter.CORetriedGen = RSData->FRSCounter.LCORetriedGen +
  1421. RSData->FRSCounter.RCORetriedGen;
  1422. RSData->FRSCounter.CORetriedFet = RSData->FRSCounter.LCORetriedFet +
  1423. RSData->FRSCounter.RCORetriedFet;
  1424. RSData->FRSCounter.CORetriedIns = RSData->FRSCounter.LCORetriedIns +
  1425. RSData->FRSCounter.RCORetriedIns;
  1426. RSData->FRSCounter.CORetriedRen = RSData->FRSCounter.LCORetriedRen +
  1427. RSData->FRSCounter.RCORetriedRen;
  1428. RSData->FRSCounter.COMorphed = RSData->FRSCounter.LCOMorphed +
  1429. RSData->FRSCounter.RCOMorphed;
  1430. RSData->FRSCounter.COPropagated = RSData->FRSCounter.LCOPropagated +
  1431. RSData->FRSCounter.RCOPropagated;
  1432. RSData->FRSCounter.COReceived = RSData->FRSCounter.RCOReceived;
  1433. RSData->FRSCounter.COSent = RSData->FRSCounter.LCOSent +
  1434. RSData->FRSCounter.RCOSent;
  1435. }