windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/cmp/asp/perfdef.h
2020-09-26 16:20:57 +08:00

830 lines
20 KiB
C++

/*===================================================================
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 <pudebug.h>
/*===================================================================
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