windows-nt/Source/XPSP1/NT/net/ias/system/perfmon/iasperf.cpp

737 lines
16 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1997, Microsoft Corp. All rights reserved.
//
// FILE
//
// iasperf.cpp
//
// SYNOPSIS
//
// This file implements the PerfMon DLL for the Everest server.
//
// MODIFICATION HISTORY
//
// 09/15/1997 Original version.
// 03/17/1998 Unmap the shared memory after each collection interval.
// 06/18/1998 Unmap view of file after each collection interval.
// 08/10/1998 Clean-up registration code.
// 09/08/1997 Conform to latest rev. of ietf draft.
// 09/11/1997 Use stats API. Add SNMP registration code.
// 10/19/1998 Throw LONG's on error.
// 01/18/1999 Do not register extension agent.
// 02/11/1999 Ref. count open & close.
// 05/13/1999 Unload previous counters before loading new ones.
// 09/23/1999 Don't create files from resource.
// 01/25/2000 Check if DLL is opend during Collect.
// 02/18/2000 Added support for proxy counters.
//
///////////////////////////////////////////////////////////////////////////////
#include <ias.h>
#include <iasinfo.h>
#include <iasutil.h>
#include <loadperf.h>
#include <newop.cpp>
#include <iasperf.h>
#include <perflib.h>
#include <resource.h>
#include <stats.h>
//////////
// Schema for the performance objects supported by this DLL.
//////////
extern PerfCollectorDef PERF_SCHEMA;
//////////
// The performance collector.
//////////
PerfCollector theCollector;
//////////
// Last start time of the server -- used to detect restarts.
//////////
LARGE_INTEGER theLastStart;
//////////
// Computes the server time counters.
//////////
PDWORD
WINAPI
ComputeServerTimes(
PDWORD dst
) throw ()
{
if (theStats->seServer.liStartTime.QuadPart)
{
LARGE_INTEGER now, elapsed;
GetSystemTimeAsFileTime((LPFILETIME)&now);
elapsed.QuadPart = now.QuadPart - theStats->seServer.liStartTime.QuadPart;
elapsed.QuadPart /= 10000000;
*dst++ = elapsed.LowPart;
elapsed.QuadPart = now.QuadPart - theStats->seServer.liResetTime.QuadPart;
elapsed.QuadPart /= 10000000;
*dst++ = elapsed.LowPart;
}
else
{
// If the start time is zero, then the server's not running.
*dst++ = 0;
*dst++ = 0;
}
return dst;
}
//////////
// Creates instances for any newly added clients.
//////////
VOID
WINAPI
PopulateInstances(
PerfObjectType& sink
) throw ()
{
for (DWORD i = sink.size(); i < theStats->dwNumClients; ++i)
{
WCHAR buf[16];
sink.addInstance(ias_inet_htow(theStats->ceClients[i].dwAddress, buf));
}
}
//////////
// Computes derived authentication counters from raw counters.
//////////
VOID
WINAPI
DeriveAuthCounters(
PDWORD dst
) throw ()
{
// Compute packets received.
DWORD rcvd = 0;
for (DWORD i = 0; i < 6; ++i) rcvd += dst[i];
dst[9] = rcvd;
// Compute packets sent.
DWORD sent = 0;
for (DWORD j = 6; j < 9; ++j) sent += dst[j];
dst[10] = sent;
// Copy raw counters into rate counters.
memcpy(dst + 11, dst, sizeof(DWORD) * 11);
}
//////////
// Computes derived accounting counters from raw counters.
//////////
VOID
WINAPI
DeriveAcctCounters(
PDWORD dst
) throw ()
{
// Compute packets received.
DWORD rcvd = 0;
for (DWORD i = 0; i < 7; ++i) rcvd += dst[i];
dst[8] = rcvd;
// Compute packets sent.
DWORD sent = 0;
for (DWORD j = 7; j < 8; ++j) sent += dst[j];
dst[9] = sent;
// Copy raw counters into rate counters.
memcpy(dst + 10, dst, sizeof(DWORD) * 10);
}
//////////
// Callback for the authentication server object.
//////////
VOID WINAPI AuthServerDataSource(PerfObjectType& sink)
{
PDWORD p = ComputeServerTimes(sink[0].getCounters());
*p++ = theStats->seServer.dwCounters[radiusAuthServTotalInvalidRequests];
*p++ = theStats->seServer.dwCounters[radiusAuthServTotalInvalidRequests];
memset(p, 0, sizeof(DWORD) * 9);
for (DWORD i = 0; i < theStats->dwNumClients; ++i)
{
for (DWORD j = 0; j < 9; ++j)
{
p[j] += theStats->ceClients[i].dwCounters[j];
}
}
DeriveAuthCounters(p);
}
//////////
// Callback for the authentication clients object.
//////////
VOID WINAPI AuthClientDataSource(PerfObjectType& sink)
{
PopulateInstances(sink);
for (DWORD i = 0; i < theStats->dwNumClients; ++i)
{
PDWORD dst = sink[i].getCounters();
memcpy(dst, theStats->ceClients[i].dwCounters, sizeof(DWORD) * 9);
DeriveAuthCounters(dst);
}
}
//////////
// Callback for the accounting server object.
//////////
VOID WINAPI AcctServerDataSource(PerfObjectType& sink)
{
PDWORD p = ComputeServerTimes(sink[0].getCounters());
*p++ = theStats->seServer.dwCounters[radiusAccServTotalInvalidRequests];
*p++ = theStats->seServer.dwCounters[radiusAccServTotalInvalidRequests];
memset(p, 0, sizeof(DWORD) * 8);
for (DWORD i = 0; i < theStats->dwNumClients; ++i)
{
for (DWORD j = 0; j < 8; ++j)
{
p[j] += theStats->ceClients[i].dwCounters[j + 9];
}
}
DeriveAcctCounters(p);
}
//////////
// Callback for the accounting clients object.
//////////
VOID WINAPI AcctClientDataSource(PerfObjectType& sink)
{
PopulateInstances(sink);
for (DWORD i = 0; i < theStats->dwNumClients; ++i)
{
PDWORD dst = sink[i].getCounters();
memcpy(dst, theStats->ceClients[i].dwCounters + 9, sizeof(DWORD) * 8);
DeriveAcctCounters(dst);
}
}
//////////
// Creates instances for any newly added remote servers.
//////////
VOID
WINAPI
PopulateServers(
PerfObjectType& sink
) throw ()
{
for (DWORD i = sink.size(); i < theProxy->dwNumRemoteServers; ++i)
{
WCHAR buf[16];
sink.addInstance(
ias_inet_htow(theProxy->rseRemoteServers[i].dwAddress, buf)
);
}
}
VOID
WINAPI
DeriveProxyAuthCounters(
PDWORD dst
) throw ()
{
// Compute packets received.
dst[12] = + dst[radiusAuthClientAccessAccepts]
+ dst[radiusAuthClientAccessRejects]
+ dst[radiusAuthClientAccessChallenges]
+ dst[radiusAuthClientUnknownTypes];
// Compute requests pending.
dst[13] = + dst[radiusAuthClientAccessRequests]
- dst[radiusAuthClientAccessAccepts]
- dst[radiusAuthClientAccessRejects]
- dst[radiusAuthClientAccessChallenges]
+ dst[radiusAuthClientMalformedAccessResponses]
+ dst[radiusAuthClientBadAuthenticators]
+ dst[radiusAuthClientPacketsDropped]
- dst[radiusAuthClientTimeouts];
// Copy raw counters into rate counters.
memcpy(dst + 14, dst + 2, sizeof(DWORD) * 10);
}
VOID
WINAPI
DeriveProxyAcctCounters(
PDWORD dst
) throw ()
{
// Compute packets received.
dst[10] = + dst[radiusAccClientResponses - 12]
+ dst[radiusAccClientUnknownTypes - 12];
// Compute requests pending.
dst[11] = + dst[radiusAccClientRequests - 12]
- dst[radiusAccClientResponses - 12]
+ dst[radiusAccClientMalformedResponses - 12]
+ dst[radiusAccClientBadAuthenticators - 12]
+ dst[radiusAccClientPacketsDropped - 12]
- dst[radiusAccClientTimeouts - 12];
// Copy raw counters into rate counters.
memcpy(dst + 12, dst + 2, sizeof(DWORD) * 8);
}
//////////
// Callback for the authentication proxy object.
//////////
VOID WINAPI AuthProxyDataSource(PerfObjectType& sink)
{
PDWORD p = sink[0].getCounters();
p[0] = theProxy->peProxy.dwCounters[radiusAuthClientInvalidAddresses];
p[1] = theProxy->peProxy.dwCounters[radiusAuthClientInvalidAddresses];
memset(p + 2, 0, sizeof(DWORD) * 10);
for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
{
for (DWORD j = 2; j < 12; ++j)
{
p[j] += theProxy->rseRemoteServers[i].dwCounters[j];
}
}
DeriveProxyAuthCounters(p);
}
//////////
// Callback for the accounting proxy object.
//////////
VOID WINAPI AcctProxyDataSource(PerfObjectType& sink)
{
PDWORD p = sink[0].getCounters();
p[0] = theProxy->peProxy.dwCounters[radiusAccClientInvalidAddresses];
p[1] = theProxy->peProxy.dwCounters[radiusAccClientInvalidAddresses];
memset(p + 2, 0, sizeof(DWORD) * 8);
for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
{
for (DWORD j = 2; j < 10; ++j)
{
p[j] += theProxy->rseRemoteServers[i].dwCounters[j + 12];
}
}
DeriveProxyAcctCounters(p);
}
//////////
// Callback for the remote authentication servers.
//////////
VOID WINAPI AuthRemoteServerDataSource(PerfObjectType& sink)
{
PopulateServers(sink);
for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
{
PDWORD dst = sink[i].getCounters();
memcpy(
dst,
theProxy->rseRemoteServers[i].dwCounters,
sizeof(DWORD) * 12
);
DeriveProxyAuthCounters(dst);
}
}
//////////
// Callback for the remote accounting servers.
//////////
VOID WINAPI AcctRemoteServerDataSource(PerfObjectType& sink)
{
PopulateServers(sink);
for (DWORD i = 0; i < theProxy->dwNumRemoteServers; ++i)
{
PDWORD dst = sink[i].getCounters();
memcpy(
dst,
theProxy->rseRemoteServers[i].dwCounters + 12,
sizeof(DWORD) * 10
);
DeriveProxyAcctCounters(dst);
}
}
//////////
// Reference count for API initialization.
//////////
LONG theRefCount;
//////////
// Serialize access to PerfMon.
//////////
CRITICAL_SECTION thePerfLock;
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// OpenPerformanceData
//
///////////////////////////////////////////////////////////////////////////////
extern "C"
DWORD
WINAPI
OpenPerformanceData(
LPWSTR lpDeviceNames
)
{
EnterCriticalSection(&thePerfLock);
DWORD error = NO_ERROR;
// Are we already initialized?
if (theRefCount == 0)
{
if (StatsOpen())
{
try
{
theCollector.open(PERF_SCHEMA);
// Everything succeeded, so update theRefCount.
theRefCount = 1;
}
catch (LONG lErr)
{
StatsClose();
error = (DWORD)lErr;
}
}
else
{
error = GetLastError();
}
}
else
{
// Already initialized, so just bump the ref. count.
++theRefCount;
}
LeaveCriticalSection(&thePerfLock);
return error;
}
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// CollectPerformanceData
//
///////////////////////////////////////////////////////////////////////////////
extern "C"
DWORD
WINAPI
CollectPerformanceData(
LPWSTR lpwszValue,
LPVOID* lppData,
LPDWORD lpcbBytes,
LPDWORD lpcObjectTypes
)
{
DWORD error = NO_ERROR;
EnterCriticalSection(&thePerfLock);
if (theRefCount)
{
StatsLock();
// If the server has restarted, then
if (theStats->seServer.liStartTime.QuadPart != theLastStart.QuadPart)
{
// ... clear out any old instances.
theCollector.clear();
theLastStart = theStats->seServer.liStartTime;
}
try
{
theCollector.collect(
lpwszValue,
*lppData,
*lpcbBytes,
*lpcObjectTypes
);
}
catch (LONG lErr)
{
error = (DWORD)lErr;
}
StatsUnlock();
}
else
{
error = ERROR_NOT_READY;
}
LeaveCriticalSection(&thePerfLock);
return error;
}
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// ClosePerformanceData
//
///////////////////////////////////////////////////////////////////////////////
extern "C"
DWORD
WINAPI
ClosePerformanceData()
{
EnterCriticalSection(&thePerfLock);
DWORD error = NO_ERROR;
if (--theRefCount == 0)
{
// We're the last man out, so clean-up.
StatsClose();
try
{
theCollector.close();
}
catch (LONG lErr)
{
error = (DWORD)lErr;
}
}
LeaveCriticalSection(&thePerfLock);
return error;
}
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// CreateKey
//
// DESCRIPTION
//
// Creates a registry key.
//
///////////////////////////////////////////////////////////////////////////////
LONG
WINAPI
CreateKey(
PCWSTR lpSubKey,
PHKEY phkResult
)
{
DWORD disposition;
return RegCreateKeyExW(
HKEY_LOCAL_MACHINE,
lpSubKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
NULL,
phkResult,
&disposition
);
}
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// SetStringValue
//
// DESCRIPTION
//
// Sets a string value on a registry key.
//
///////////////////////////////////////////////////////////////////////////////
LONG
WINAPI
SetStringValue(
HKEY hKey,
PCWSTR lpValueName,
DWORD dwType,
PCWSTR lpData
)
{
return RegSetValueEx(
hKey,
lpValueName,
0,
dwType,
(CONST BYTE*)lpData,
sizeof(WCHAR) * (wcslen(lpData) + 1)
);
}
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// DllRegisterServer
//
// DESCRIPTION
//
// Adds entries to the system registry.
//
///////////////////////////////////////////////////////////////////////////////
const WCHAR MODULE[] =
L"%SystemRoot%\\System32\\iasperf.dll";
const WCHAR PERF_KEY[] =
L"SYSTEM\\CurrentControlSet\\Services\\IAS\\Performance";
extern "C"
STDAPI DllRegisterServer(void)
{
LONG error;
HKEY hKey;
DWORD disposition;
//////////
// Blow away the existing counters ...
//////////
UnloadPerfCounterTextStringsW(L"LODCTR " IASServiceName, TRUE);
//////////
// Update the PerfMon registry entries.
//////////
error = CreateKey(PERF_KEY, &hKey);
if (error) { return HRESULT_FROM_WIN32(error); }
SetStringValue(hKey, L"Library", REG_EXPAND_SZ, MODULE);
SetStringValue(hKey, L"Open", REG_SZ, L"OpenPerformanceData");
SetStringValue(hKey, L"Close", REG_SZ, L"ClosePerformanceData");
SetStringValue(hKey, L"Collect", REG_SZ, L"CollectPerformanceData");
RegCloseKey(hKey);
//////////
// Install the counters.
//////////
LONG ErrorCode = LoadPerfCounterTextStringsW(L"LODCTR IASPERF.INI", TRUE);
if (ErrorCode == ERROR_ALREADY_EXISTS) { ErrorCode = NO_ERROR; }
return HRESULT_FROM_WIN32(ErrorCode);
}
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// DllUnregisterServer
//
// DESCRIPTION
//
// Removes entries from the system registry.
//
///////////////////////////////////////////////////////////////////////////////
extern "C"
STDAPI DllUnregisterServer(void)
{
LONG error;
HKEY hKey;
/////////
// Unload the text strings.
/////////
UnloadPerfCounterTextStringsW(L"LODCTR " IASServiceName, TRUE);
//////////
// Delete the PerfMon registry key.
//////////
error = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Services\\IAS",
0,
KEY_CREATE_SUB_KEY,
&hKey
);
if (error == NO_ERROR)
{
RegDeleteKey(hKey, L"Performance");
RegCloseKey(hKey);
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// DllMain
//
///////////////////////////////////////////////////////////////////////////////
extern "C"
BOOL
WINAPI
DllMain(
HINSTANCE hInstance,
DWORD dwReason,
LPVOID /*lpReserved*/
)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hInstance);
InitializeCriticalSectionAndSpinCount(&thePerfLock, 0x80001000);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
DeleteCriticalSection(&thePerfLock);
}
return TRUE;
}