/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000, Microsoft Corp. All rights reserved. // // FILE // // counters.cpp // // SYNOPSIS // // Defines the classes SharedMemory and ProxyCounters. // // MODIFICATION HISTORY // // 02/16/2000 Original version. // /////////////////////////////////////////////////////////////////////////////// #include #include ////////// // Helper function that creates a named mutex which only admins can access. ////////// HANDLE CreateAdminMutex(PCWSTR name) 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. return CreateMutex(&sa, FALSE, name); } SharedMemory::SharedMemory() throw () : fileMap(NULL), view(NULL), reserved(0), committed(0) { // Determine the page size for this platform. SYSTEM_INFO si; GetSystemInfo(&si); pageSize = si.dwPageSize; } bool SharedMemory::open(PCWSTR name, DWORD size) throw () { close(); // Determine the number of pages to reserve. reserved = (size + pageSize - 1)/pageSize; // Create the mapping in the pagefile ... fileMap = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0, reserved * pageSize, name ); if (fileMap) { // ... and map it into our process. view = MapViewOfFile( fileMap, FILE_MAP_WRITE, 0, 0, 0 ); if (!view) { CloseHandle(fileMap); fileMap = NULL; } } return view != NULL; } void SharedMemory::close() throw () { if (view) { UnmapViewOfFile(view); view = NULL; } if (fileMap) { CloseHandle(fileMap); fileMap = NULL; } reserved = 0; committed = 0; } bool SharedMemory::commit(DWORD nbyte) throw () { // How many pages will we need ? DWORD pagesNeeded = (nbyte + 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( view, pageSize * pagesNeeded, MEM_COMMIT, PAGE_READWRITE )) { return false; } committed = pagesNeeded; } return true; } HRESULT ProxyCounters::FinalConstruct() throw () { mutex = CreateAdminMutex(RadiusStatisticsMutex); if (mutex) { lock(); // Opend the shared memory. if (data.open(RadiusProxyStatisticsName, 0x40000)) { // Commit enough space for the Proxy entry. nbyte = sizeof(RadiusProxyStatistics) - sizeof(RadiusRemoteServerEntry); if (data.commit(nbyte)) { // Zero out the stats. stats = (RadiusProxyStatistics*)data.base(); memset(stats, 0, nbyte); } } unlock(); } if (!stats) { DWORD error = GetLastError(); return HRESULT_FROM_WIN32(error); } return S_OK; } RadiusRemoteServerEntry* ProxyCounters::getRemoteServerEntry( ULONG address ) throw () { address = ntohl(address); // Try once without the lock. RadiusRemoteServerEntry* entry = findRemoteServer(address); if (!entry) { lock(); // Now try again with the lock just to be sure. entry = findRemoteServer(address); if (!entry) { // Make sure we have space. if (data.commit(nbyte + sizeof(RadiusRemoteServerEntry))) { // Zero out the new entry. entry = stats->rseRemoteServers + stats->dwNumRemoteServers; memset(entry, 0, sizeof(*entry)); // Set the address. entry->dwAddress = address; // Update the number of servers ... ++(stats->dwNumRemoteServers); // ... and the number of bytes. nbyte += sizeof(RadiusRemoteServerEntry); } } unlock(); } return entry; } ////////// // Array that maps a (RadiusMIB, RadiusEvent) pair to a RemoteServer counter // offset. ////////// LONG counterOffset[][2] = { // eventNone { -1, -1 }, // eventInvalidAddress { radiusAuthClientInvalidAddresses, radiusAccClientInvalidAddresses }, // eventAccessRequest { radiusAuthClientAccessRequests, -1 }, // eventAccessAccept { radiusAuthClientAccessAccepts, -1 }, // eventAccessReject { radiusAuthClientAccessRejects, -1 }, // eventAccessChallenge { radiusAuthClientAccessChallenges, -1 }, // eventAccountingRequest { -1, radiusAccClientRequests }, // eventAccountingResponse { -1, radiusAccClientResponses }, // eventMalformedPacket { radiusAuthClientMalformedAccessResponses, radiusAccClientResponses }, // eventBadAuthenticator { radiusAuthClientBadAuthenticators, radiusAccClientBadAuthenticators }, // eventBadSignature { radiusAuthClientBadAuthenticators, radiusAccClientBadAuthenticators }, // eventMissingSignature { radiusAuthClientBadAuthenticators, radiusAccClientBadAuthenticators }, // eventTimeout { radiusAuthClientTimeouts, radiusAccClientTimeouts }, // eventUnknownType { radiusAuthClientUnknownTypes, radiusAccClientUnknownTypes }, // eventUnexpectedResponse { radiusAuthClientPacketsDropped, radiusAccClientPacketsDropped }, // eventLateResponse { radiusAuthClientPacketsDropped, radiusAccClientPacketsDropped }, // eventRoundTrip { radiusAuthClientRoundTripTime, radiusAccClientRoundTripTime }, // eventSendError { -1, -1 }, // eventReceiveError { -1, -1 }, // eventServerAvailable { -1, -1 }, // eventServerUnavailable { -1, -1 } }; void ProxyCounters::updateCounters( RadiusPortType port, RadiusEventType event, RadiusRemoteServerEntry* server, ULONG data ) throw () { // Get the counter offset. If it's negative, then this event doesn't effect // any counters. LONG offset = counterOffset[event][port]; if (offset < 0) { return; } if (event == eventInvalidAddress) { InterlockedIncrement((PLONG)stats->peProxy.dwCounters + offset); } else if (server) { if (event == eventRoundTrip) { server->dwCounters[offset] = data; } else { InterlockedIncrement((PLONG)server->dwCounters + offset); } } } RadiusRemoteServerEntry* ProxyCounters::findRemoteServer( ULONG address ) throw () { for (DWORD i = 0; i < stats->dwNumRemoteServers; ++i) { if (stats->rseRemoteServers[i].dwAddress == address) { return stats->rseRemoteServers + i; } } return NULL; }