|
|
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1997, Microsoft Corp. All rights reserved.
//
// FILE
//
// InfoShare.cpp
//
// SYNOPSIS
//
// This file implements the class InfoShare.
//
// MODIFICATION HISTORY
//
// 09/09/1997 Original version.
// 03/17/1998 Clear data structure at startup and shutdown.
// 04/20/1998 Check if the shared memory is mapped during finalize().
// 09/09/1998 Protect client changes with a shared Mutex.
// 09/17/1998 Fix resize bug.
// 09/28/1999 Only allow Administrators access to mutex.
// 05/19/2000 Fix bug calculating bytes needed.
//
///////////////////////////////////////////////////////////////////////////////
#include <iascore.h>
#include <iasutil.h>
#include <InfoShare.h>
//////////
// The maximum size of the shared memory segment.
//////////
const DWORD MAX_INFO_SIZE = 0x100000;
InfoShare::InfoShare() throw () : monitor(NULL), pageSize(0), committed(0), reserved(0), fileMap(NULL), info(NULL) { }
InfoShare::~InfoShare() throw () { if (info != NULL) { UnmapViewOfFile(info); }
if (fileMap != NULL) { CloseHandle(fileMap); }
if (monitor != NULL) { CloseHandle(monitor); } }
RadiusClientEntry* InfoShare::findClientEntry(PCWSTR inetAddress) throw () { if (!info) { return NULL; }
DWORD address = ias_inet_wtoh(inetAddress);
ClientMap::iterator i = clients.find(address);
// If we found it, return it. Otherwise add a new entry.
return i != clients.end() ? i->second : addClientEntry(address); }
void InfoShare::onReset() throw () { if (info) { GetSystemTimeAsFileTime((LPFILETIME)&info->seServer.liResetTime); } }
bool InfoShare::initialize() throw () { // Create the SID for local Administrators.
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY; PSID adminSid = (PSID)_alloca(GetSidLengthRequired(2)); InitializeSid( adminSid, &sia, 2 ); *GetSidSubAuthority(adminSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; *GetSidSubAuthority(adminSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
// Create an ACL giving Administrators all access.
ULONG cbAcl = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetLengthSid(adminSid); PACL acl = (PACL)_alloca(cbAcl); InitializeAcl( acl, cbAcl, ACL_REVISION ); AddAccessAllowedAce( acl, ACL_REVISION, MUTEX_ALL_ACCESS, adminSid );
// Create a security descriptor with the above ACL.
PSECURITY_DESCRIPTOR pSD; BYTE buffer[SECURITY_DESCRIPTOR_MIN_LENGTH]; pSD = (PSECURITY_DESCRIPTOR)buffer; InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(pSD, TRUE, acl, FALSE);
// Fill in the SECURITY_ATTRIBUTES struct.
SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = TRUE;
// Create the mutex.
monitor = CreateMutex( &sa, FALSE, RadiusStatisticsMutex ); if (!monitor) { return false; }
// Determine the page size for this platform.
SYSTEM_INFO si; GetSystemInfo(&si); pageSize = si.dwPageSize;
// Determine the number of pages to reserve.
reserved = (MAX_INFO_SIZE + pageSize - 1)/pageSize;
// Create the mapping in the pagefile ...
PVOID view; fileMap = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0, reserved * pageSize, RadiusStatisticsName ); if (!fileMap) { goto close_mutex; }
// ... and map it into our process.
view = MapViewOfFile( fileMap, FILE_MAP_WRITE, 0, 0, 0 ); if (!view) { goto close_map; }
// Commit the first page.
info = (RadiusStatistics*)VirtualAlloc( view, pageSize, MEM_COMMIT, PAGE_READWRITE ); if (!info) { goto unmap_view; } committed = 1;
Lock();
// Zero out any data from a previous incarnation.
clear();
// Record our start and reset times.
GetSystemTimeAsFileTime((LPFILETIME)&info->seServer.liStartTime); info->seServer.liResetTime = info->seServer.liStartTime;
Unlock();
return true;
unmap_view: UnmapViewOfFile(view);
close_map: CloseHandle(fileMap); fileMap = NULL;
close_mutex: CloseHandle(monitor); monitor = NULL;
return false; }
void InfoShare::finalize() { clear();
UnmapViewOfFile(info); info = NULL;
CloseHandle(fileMap); fileMap = NULL;
CloseHandle(monitor); monitor = NULL; }
RadiusClientEntry* InfoShare::addClientEntry(DWORD address) throw () { Guard<InfoShare> guard(*this);
// Double check that the client doesn't exist now that we're serialized.
ClientMap::iterator i = clients.find(address); if (i != clients.end()) { return i->second; }
// How many bytes will we need to add the new entry?
DWORD newSize = (info->dwNumClients) * sizeof(RadiusClientEntry) + sizeof(RadiusStatistics);
// How many pages will we need to add the new entry?
DWORD pagesNeeded = (newSize + pageSize - 1)/pageSize;
// Do we have to commit more memory?
if (pagesNeeded > committed) { // If we've hit the max or we can't commit anymore, we're done.
if (pagesNeeded > reserved || !VirtualAlloc(info, pageSize * pagesNeeded, MEM_COMMIT, PAGE_READWRITE)) { return NULL; }
committed = pagesNeeded; }
// Get the next client entry.
RadiusClientEntry* pce = info->ceClients + info->dwNumClients;
// Make sure it's zero'ed.
memset(pce, 0, sizeof(RadiusClientEntry));
// Set the address.
pce->dwAddress = address;
try { // Insert it into the index.
clients[address] = pce; } catch (std::bad_alloc) { return NULL; }
// Safefly inserted into the index, so increment the number of clients.
++(info->dwNumClients);
return pce; }
void InfoShare::clear() throw () { Lock();
if (info) { memset(info, 0, sizeof(RadiusStatistics)); }
Unlock(); }
|