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.

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