/*=================================================================== Microsoft Denali Microsoft Confidential. Copyright 1996 Microsoft Corporation. All Rights Reserved. Component: Main File: perfdef.h Owner: DmitryR Data definitions shared between asp.dll and aspperf.dll ===================================================================*/ #ifndef _ASP_PERFDEF_H #define _ASP_PERFDEF_H #include /*=================================================================== Definitions of names, sizes and mapped data block structures ===================================================================*/ // Mutex name to access the main file map #define SZ_PERF_MUTEX "Global\\ASP_PERFMON_MUTEX" // WaitForSingleObject arg (how long to wait for mutext before failing) #define PERM_MUTEX_WAIT 1000 // Main shared file map name #define SZ_PERF_MAIN_FILEMAP "Global\\ASP_PERFMON_MAIN_BLOCK" // Max number of registered (ASP) processes in main file map #define C_PERF_PROC_MAX 1024 // Structure that defines main file map struct CPerfMainBlockData { DWORD m_dwTimestamp; // time (GetTickCount()) of the last change DWORD m_cItems; // number of registred processes // array of process WAM CLS IDs CLSID m_rgClsIds[C_PERF_PROC_MAX]; }; #define CB_PERF_MAIN_BLOCK (sizeof(struct CPerfMainBlockData)) // Name for per-process file map #define SZ_PERF_PROC_FILEMAP_PREFIX "Global\\ASP_PERFMON_BLOCK_" #define CCH_PERF_PROC_FILEMAP_PREFIX 25 // Number of counters in per-process file map #define C_PERF_PROC_COUNTERS 37 struct CPerfProcBlockData { CLSID m_ClsId; // process CLS ID DWORD m_rgdwCounters[C_PERF_PROC_COUNTERS]; // array counters }; #define CB_PERF_PROC_BLOCK (sizeof(struct CPerfProcBlockData)) #define CB_COUNTERS (sizeof(DWORD) * C_PERF_PROC_COUNTERS) /*=================================================================== CSharedMemBlock -- generic shared memory block ===================================================================*/ class CSharedMemBlock { private: HANDLE m_hMemory; void *m_pMemory; protected: SECURITY_ATTRIBUTES m_sa; public: inline CSharedMemBlock() : m_hMemory(NULL), m_pMemory(NULL) { m_sa.nLength = sizeof(SECURITY_ATTRIBUTES); m_sa.lpSecurityDescriptor = NULL; m_sa.bInheritHandle = FALSE; } inline ~CSharedMemBlock() { UnInitMap(); if (m_sa.lpSecurityDescriptor) free(m_sa.lpSecurityDescriptor); } inline void *PMemory() { return m_pMemory; } HRESULT InitSD(); HRESULT InitMap(LPCSTR szName, DWORD dwSize); HRESULT UnInitMap(); private: HRESULT CreateSids( PSID *ppBuiltInAdministrators, PSID *ppPowerUsers, PSID *ppAuthenticatedUsers); }; // // CreateSids // // Create 3 Security IDs // // Caller must free memory allocated to SIDs on success. // // Returns: HRESULT indicating SUCCESS or FAILURE // inline HRESULT CSharedMemBlock::CreateSids( PSID *ppBuiltInAdministrators, PSID *ppPowerUsers, PSID *ppAuthenticatedUsers ) { HRESULT hr = S_OK; *ppBuiltInAdministrators = NULL; *ppPowerUsers = NULL; *ppAuthenticatedUsers = NULL; // // An SID is built from an Identifier Authority and a set of Relative IDs // (RIDs). The Authority of interest to us SECURITY_NT_AUTHORITY. // SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; // // Each RID represents a sub-unit of the authority. Two of the SIDs we // want to build, Local Administrators, and Power Users, are in the "built // in" domain. The other SID, for Authenticated users, is based directly // off of the authority. // // For examples of other useful SIDs consult the list in // \nt\public\sdk\inc\ntseapi.h. // if (!AllocateAndInitializeSid(&NtAuthority, 2, // 2 sub-authorities SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, ppBuiltInAdministrators)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (!AllocateAndInitializeSid(&NtAuthority, 2, // 2 sub-authorities SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0,0,0,0,0,0, ppPowerUsers)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (!AllocateAndInitializeSid(&NtAuthority, 1, // 1 sub-authority SECURITY_AUTHENTICATED_USER_RID, 0,0,0,0,0,0,0, ppAuthenticatedUsers)) { hr = HRESULT_FROM_WIN32(GetLastError()); } if (FAILED(hr)) { if (*ppBuiltInAdministrators) { FreeSid(*ppBuiltInAdministrators); *ppBuiltInAdministrators = NULL; } if (*ppPowerUsers) { FreeSid(*ppPowerUsers); *ppPowerUsers = NULL; } if (*ppAuthenticatedUsers) { FreeSid(*ppAuthenticatedUsers); *ppAuthenticatedUsers = NULL; } } return hr; } // // InitSD // // Creates a SECURITY_DESCRIPTOR with specific DACLs. // inline HRESULT CSharedMemBlock::InitSD() { HRESULT hr = S_OK; PSID pAuthenticatedUsers = NULL; PSID pBuiltInAdministrators = NULL; PSID pPowerUsers = NULL; PSECURITY_DESCRIPTOR pSD = NULL; if (m_sa.lpSecurityDescriptor != NULL) { return S_OK; } if (FAILED(hr = CreateSids(&pBuiltInAdministrators, &pPowerUsers, &pAuthenticatedUsers))); else { // // Calculate the size of and allocate a buffer for the DACL, we need // this value independently of the total alloc size for ACL init. // ULONG AclSize; // // "- sizeof (ULONG)" represents the SidStart field of the // ACCESS_ALLOWED_ACE. Since we're adding the entire length of the // SID, this field is counted twice. // AclSize = sizeof (ACL) + (3 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG))) + GetLengthSid(pAuthenticatedUsers) + GetLengthSid(pBuiltInAdministrators) + GetLengthSid(pPowerUsers); pSD = malloc(SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize); if (!pSD) { hr = E_OUTOFMEMORY; } else { ACL *Acl; Acl = (ACL *)((BYTE *)pSD + SECURITY_DESCRIPTOR_MIN_LENGTH); if (!InitializeAcl(Acl, AclSize, ACL_REVISION)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (!AddAccessAllowedAce(Acl, ACL_REVISION, SYNCHRONIZE | GENERIC_ALL, pAuthenticatedUsers)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (!AddAccessAllowedAce(Acl, ACL_REVISION, SYNCHRONIZE | GENERIC_ALL, pPowerUsers)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (!AddAccessAllowedAce(Acl, ACL_REVISION, SYNCHRONIZE | GENERIC_ALL, pBuiltInAdministrators)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (!SetSecurityDescriptorDacl(pSD, TRUE, Acl, FALSE)) { hr = HRESULT_FROM_WIN32(GetLastError()); } } } if (pAuthenticatedUsers) FreeSid(pAuthenticatedUsers); if (pBuiltInAdministrators) FreeSid(pBuiltInAdministrators); if (pPowerUsers) FreeSid(pPowerUsers); if (FAILED(hr) && pSD) { free(pSD); pSD = NULL; } m_sa.lpSecurityDescriptor = pSD; return hr; } inline HRESULT CSharedMemBlock::InitMap ( LPCSTR szName, DWORD dwSize ) { BOOL fNew = FALSE; HRESULT hr = S_OK; if (FAILED(hr = InitSD())) { return hr; } // Try to open existing m_hMemory = OpenFileMappingA ( FILE_MAP_ALL_ACCESS, FALSE, szName ); if (!m_hMemory) { m_hMemory = CreateFileMappingA ( INVALID_HANDLE_VALUE, &m_sa, PAGE_READWRITE, 0, dwSize, szName ); fNew = TRUE; } if (!m_hMemory) return E_FAIL; m_pMemory = MapViewOfFile ( m_hMemory, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); if (!m_pMemory) { UnInitMap(); return E_FAIL; } if (fNew) memset(m_pMemory, 0, dwSize); return S_OK; } inline HRESULT CSharedMemBlock::UnInitMap() { if (m_pMemory) { UnmapViewOfFile(m_pMemory); m_pMemory = NULL; } if (m_hMemory) { CloseHandle(m_hMemory); m_hMemory = NULL; } return S_OK; } /*=================================================================== CPerfProcBlock - class representing pref data for a single process ===================================================================*/ class CPerfProcBlock : public CSharedMemBlock { friend class CPerfMainBlock; protected: DWORD m_fInited : 1; DWORD m_fMemCSInited : 1; DWORD m_fReqCSInited : 1; // critical sections (only used in ASP.DLL) CRITICAL_SECTION m_csMemLock; // CS for memory counters CRITICAL_SECTION m_csReqLock; // CS for per-request counters // block of counters CPerfProcBlockData *m_pData; // next process data (used in ASPPERF.DLL) CPerfProcBlock *m_pNext; // access shared memory HRESULT MapMemory(const CLSID &ClsId); public: inline CPerfProcBlock() : m_fInited(FALSE), m_fMemCSInited(FALSE), m_fReqCSInited(FALSE), m_pData(NULL), m_pNext(NULL) {} inline ~CPerfProcBlock() { UnInit(); } HRESULT InitCriticalSections(); HRESULT InitExternal(const CLSID &ClsId); // from ASPPERF.DLL HRESULT InitForThisProcess // from ASP.DLL ( const CLSID &ClsId, DWORD *pdwInitCounters = NULL ); HRESULT UnInit(); }; inline HRESULT CPerfProcBlock::MapMemory ( const CLSID &ClsId ) { // Construct unique map name with CLSID char szMapName[CCH_PERF_PROC_FILEMAP_PREFIX+32+1]; strcpy(szMapName, SZ_PERF_PROC_FILEMAP_PREFIX); char *pszHex = szMapName + CCH_PERF_PROC_FILEMAP_PREFIX; DWORD *pdwHex = (DWORD *)&ClsId; for (int i = 0; i < 4; i++, pszHex += 8, pdwHex++) sprintf(pszHex, "%08x", *pdwHex); // create or open the map HRESULT hr = InitMap(szMapName, CB_PERF_PROC_BLOCK); if (SUCCEEDED(hr)) { m_pData = (CPerfProcBlockData *)PMemory(); if (m_pData->m_ClsId == CLSID_NULL) m_pData->m_ClsId = ClsId; else if (m_pData->m_ClsId != ClsId) hr = E_FAIL; // cls id mismatch } return hr; } inline HRESULT CPerfProcBlock::InitCriticalSections() { HRESULT hr = S_OK; if (!m_fMemCSInited) { __try { INITIALIZE_CRITICAL_SECTION(&m_csMemLock); } __except(1) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) m_fMemCSInited = TRUE; else return hr; } if (!m_fReqCSInited) { __try { INITIALIZE_CRITICAL_SECTION(&m_csReqLock); } __except(1) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) m_fReqCSInited = TRUE; else return hr; } return S_OK; } inline HRESULT CPerfProcBlock::InitExternal ( const CLSID &ClsId ) { HRESULT hr = MapMemory(ClsId); if (SUCCEEDED(hr)) m_fInited = TRUE; else UnInit(); return hr; } inline HRESULT CPerfProcBlock::InitForThisProcess ( const CLSID &ClsId, DWORD *pdwInitCounters ) { HRESULT hr = S_OK; // Map the shared memory if (SUCCEEDED(hr)) hr = MapMemory(ClsId); if (SUCCEEDED(hr)) { // init the counters if (pdwInitCounters) memcpy(m_pData->m_rgdwCounters, pdwInitCounters, CB_COUNTERS); else memset(m_pData->m_rgdwCounters, 0, CB_COUNTERS); m_fInited = TRUE; } else { UnInit(); } return hr; } inline HRESULT CPerfProcBlock::UnInit() { if (m_fMemCSInited) { DeleteCriticalSection(&m_csMemLock); m_fMemCSInited = FALSE; } if (m_fReqCSInited) { DeleteCriticalSection(&m_csReqLock); m_fReqCSInited = FALSE; } UnInitMap(); m_pData = NULL; m_pNext = NULL; m_fInited = FALSE; return S_OK; } /*=================================================================== CPerfMainBlock - class representing the main perf data ===================================================================*/ class CPerfMainBlock : public CSharedMemBlock { private: DWORD m_fInited : 1; // the process block directory CPerfMainBlockData *m_pData; // mutex to access the process block directory HANDLE m_hMutex; // first process data (used in ASPPERF.DLL) CPerfProcBlock *m_pProcBlock; // timestamp of main block when the list of process blocks // last loaded -- to make decide to reload (ASPPREF.DLL only) DWORD m_dwTimestamp; public: inline CPerfMainBlock() : m_fInited(FALSE), m_pData(NULL), m_hMutex(NULL), m_pProcBlock(NULL), m_dwTimestamp(NULL) {} inline ~CPerfMainBlock() { UnInit(); } HRESULT Init(); HRESULT UnInit(); // lock / unlock using mutex HRESULT Lock(); HRESULT UnLock(); // add/remove process record to the main block (used from ASP.DLL) HRESULT AddProcess(const CLSID &ClsId); HRESULT RemoveProcess(const CLSID &ClsId); // load CPerfProcBlock blocks from the main block into // objects (used from APPPREF.DLL) HRESULT Load(); // gather (sum-up) the statistics from each proc block HRESULT GetStats(DWORD *pdwCounters); }; inline HRESULT CPerfMainBlock::Init() { HRESULT hr = S_OK; if (FAILED(hr = InitSD())) { return hr; } m_hMutex = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, SZ_PERF_MUTEX); if (!m_hMutex) { m_hMutex = CreateMutexA(&m_sa, FALSE, SZ_PERF_MUTEX); } if (!m_hMutex) hr = E_FAIL; if (SUCCEEDED(hr)) { hr = InitMap(SZ_PERF_MAIN_FILEMAP, CB_PERF_MAIN_BLOCK); if (SUCCEEDED(hr)) m_pData = (CPerfMainBlockData *)PMemory(); } if (SUCCEEDED(hr)) m_fInited = TRUE; else UnInit(); return hr; } inline HRESULT CPerfMainBlock::UnInit() { while (m_pProcBlock) { CPerfProcBlock *pNext = m_pProcBlock->m_pNext; m_pProcBlock->UnInit(); delete m_pProcBlock; m_pProcBlock = pNext; } if (m_hMutex) { CloseHandle(m_hMutex); m_hMutex = NULL; } UnInitMap(); m_dwTimestamp = 0; m_pData = NULL; m_pProcBlock = NULL; m_fInited = FALSE; return S_OK; } inline HRESULT CPerfMainBlock::Lock() { if (!m_hMutex) return E_FAIL; if (WaitForSingleObject(m_hMutex, PERM_MUTEX_WAIT) == WAIT_TIMEOUT) return E_FAIL; return S_OK; } inline HRESULT CPerfMainBlock::UnLock() { if (m_hMutex) ReleaseMutex(m_hMutex); return S_OK; } inline HRESULT CPerfMainBlock::AddProcess ( const CLSID &ClsId ) { if (!m_fInited) return E_FAIL; if (FAILED(Lock())) // lock mutex return E_FAIL; HRESULT hr = S_OK; BOOL fFound = FALSE; // find for (DWORD i = 0; i < m_pData->m_cItems; i++) { if (m_pData->m_rgClsIds[i] == ClsId) { fFound = TRUE; break; } } // add only if not already there if (!fFound) { if (m_pData->m_cItems < C_PERF_PROC_MAX) { m_pData->m_rgClsIds[m_pData->m_cItems] = ClsId; m_pData->m_cItems++; m_pData->m_dwTimestamp = GetTickCount(); } else { hr = E_OUTOFMEMORY; } } UnLock(); // unlock mutex return hr; } inline HRESULT CPerfMainBlock::RemoveProcess ( const CLSID &ClsId ) { if (!m_fInited) return E_FAIL; if (FAILED(Lock())) // lock mutex return E_FAIL; HRESULT hr = S_OK; int iFound = -1; // find for (DWORD i = 0; i < m_pData->m_cItems; i++) { if (m_pData->m_rgClsIds[i] == ClsId) { iFound = i; break; } } // remove if (iFound >= 0) { for (i = iFound; i < m_pData->m_cItems-1; i++) m_pData->m_rgClsIds[i] = m_pData->m_rgClsIds[i+1]; m_pData->m_cItems--; m_pData->m_dwTimestamp = GetTickCount(); } UnLock(); // unlock mutex return hr; } inline HRESULT CPerfMainBlock::Load() { if (!m_fInited) return E_FAIL; if (m_dwTimestamp == m_pData->m_dwTimestamp) return S_OK; // already up-to-date // clear out what we have while (m_pProcBlock) { CPerfProcBlock *pNext = m_pProcBlock->m_pNext; m_pProcBlock->UnInit(); delete m_pProcBlock; m_pProcBlock = pNext; } if (FAILED(Lock())) // lock mutex return E_FAIL; HRESULT hr = S_OK; // populate new objects for blocks for (DWORD i = 0; i < m_pData->m_cItems; i++) { CPerfProcBlock *pBlock = new CPerfProcBlock; if (!pBlock) { hr = E_OUTOFMEMORY; break; } hr = pBlock->InitExternal(m_pData->m_rgClsIds[i]); if (FAILED(hr)) { delete pBlock; continue; } pBlock->m_pNext = m_pProcBlock; m_pProcBlock = pBlock; } // remember timestamp m_dwTimestamp = SUCCEEDED(hr) ? m_pData->m_dwTimestamp : 0; UnLock(); // unlock mutex return hr; } inline HRESULT CPerfMainBlock::GetStats ( DWORD *pdwCounters ) { if (!m_fInited) return E_FAIL; // reload if needed if (FAILED(Load())) return E_FAIL; // init memset(pdwCounters, 0, CB_COUNTERS); // gather CPerfProcBlock *pBlock = m_pProcBlock; while (pBlock) { for (int i = 0; i < C_PERF_PROC_COUNTERS; i++) pdwCounters[i] += pBlock->m_pData->m_rgdwCounters[i]; pBlock = pBlock->m_pNext; } return S_OK; } #endif // _ASP_PERFDEF_H