Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

324 lines
8.1 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // counters.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the classes SharedMemory and ProxyCounters.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 02/16/2000 Original version.
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include <proxypch.h>
  19. #include <counters.h>
  20. //////////
  21. // Helper function that creates a named mutex which only admins can access.
  22. //////////
  23. HANDLE CreateAdminMutex(PCWSTR name) throw ()
  24. {
  25. // Create the SID for local Administrators.
  26. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  27. PSID adminSid = (PSID)_alloca(GetSidLengthRequired(2));
  28. InitializeSid(
  29. adminSid,
  30. &sia,
  31. 2
  32. );
  33. *GetSidSubAuthority(adminSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
  34. *GetSidSubAuthority(adminSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
  35. // Create an ACL giving Administrators all access.
  36. ULONG cbAcl = sizeof(ACL) +
  37. (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  38. GetLengthSid(adminSid);
  39. PACL acl = (PACL)_alloca(cbAcl);
  40. InitializeAcl(
  41. acl,
  42. cbAcl,
  43. ACL_REVISION
  44. );
  45. AddAccessAllowedAce(
  46. acl,
  47. ACL_REVISION,
  48. MUTEX_ALL_ACCESS,
  49. adminSid
  50. );
  51. // Create a security descriptor with the above ACL.
  52. PSECURITY_DESCRIPTOR pSD;
  53. BYTE buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  54. pSD = (PSECURITY_DESCRIPTOR)buffer;
  55. InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
  56. SetSecurityDescriptorDacl(pSD, TRUE, acl, FALSE);
  57. // Fill in the SECURITY_ATTRIBUTES struct.
  58. SECURITY_ATTRIBUTES sa;
  59. sa.nLength = sizeof(sa);
  60. sa.lpSecurityDescriptor = pSD;
  61. sa.bInheritHandle = TRUE;
  62. // Create the mutex.
  63. return CreateMutex(&sa, FALSE, name);
  64. }
  65. SharedMemory::SharedMemory() throw ()
  66. : fileMap(NULL),
  67. view(NULL),
  68. reserved(0),
  69. committed(0)
  70. {
  71. // Determine the page size for this platform.
  72. SYSTEM_INFO si;
  73. GetSystemInfo(&si);
  74. pageSize = si.dwPageSize;
  75. }
  76. bool SharedMemory::open(PCWSTR name, DWORD size) throw ()
  77. {
  78. close();
  79. // Determine the number of pages to reserve.
  80. reserved = (size + pageSize - 1)/pageSize;
  81. // Create the mapping in the pagefile ...
  82. fileMap = CreateFileMappingW(
  83. INVALID_HANDLE_VALUE,
  84. NULL,
  85. PAGE_READWRITE | SEC_RESERVE,
  86. 0,
  87. reserved * pageSize,
  88. name
  89. );
  90. if (fileMap)
  91. {
  92. // ... and map it into our process.
  93. view = MapViewOfFile(
  94. fileMap,
  95. FILE_MAP_WRITE,
  96. 0,
  97. 0,
  98. 0
  99. );
  100. if (!view)
  101. {
  102. CloseHandle(fileMap);
  103. fileMap = NULL;
  104. }
  105. }
  106. return view != NULL;
  107. }
  108. void SharedMemory::close() throw ()
  109. {
  110. if (fileMap)
  111. {
  112. CloseHandle(fileMap);
  113. fileMap = NULL;
  114. }
  115. view = NULL;
  116. reserved = 0;
  117. committed = 0;
  118. }
  119. bool SharedMemory::commit(DWORD nbyte) throw ()
  120. {
  121. // How many pages will we need ?
  122. DWORD pagesNeeded = (nbyte + pageSize - 1)/pageSize;
  123. // Do we have to commit more memory?
  124. if (pagesNeeded > committed)
  125. {
  126. // If we've hit the max or we can't commit anymore, we're done.
  127. if (pagesNeeded > reserved ||
  128. !VirtualAlloc(
  129. view,
  130. pageSize * pagesNeeded,
  131. MEM_COMMIT,
  132. PAGE_READWRITE
  133. ))
  134. {
  135. return false;
  136. }
  137. committed = pagesNeeded;
  138. }
  139. return true;
  140. }
  141. HRESULT ProxyCounters::FinalConstruct() throw ()
  142. {
  143. mutex = CreateAdminMutex(RadiusStatisticsMutex);
  144. if (mutex)
  145. {
  146. lock();
  147. // Opend the shared memory.
  148. if (data.open(RadiusProxyStatisticsName, 0x40000))
  149. {
  150. // Commit enough space for the Proxy entry.
  151. nbyte = sizeof(RadiusProxyStatistics) -
  152. sizeof(RadiusRemoteServerEntry);
  153. if (data.commit(nbyte))
  154. {
  155. // Zero out the stats.
  156. stats = (RadiusProxyStatistics*)data.base();
  157. memset(stats, 0, nbyte);
  158. }
  159. }
  160. unlock();
  161. }
  162. if (!stats)
  163. {
  164. DWORD error = GetLastError();
  165. return HRESULT_FROM_WIN32(error);
  166. }
  167. return S_OK;
  168. }
  169. RadiusRemoteServerEntry* ProxyCounters::getRemoteServerEntry(
  170. ULONG address
  171. ) throw ()
  172. {
  173. address = ntohl(address);
  174. // Try once without the lock.
  175. RadiusRemoteServerEntry* entry = findRemoteServer(address);
  176. if (!entry)
  177. {
  178. lock();
  179. // Now try again with the lock just to be sure.
  180. entry = findRemoteServer(address);
  181. if (!entry)
  182. {
  183. // Make sure we have space.
  184. if (data.commit(nbyte + sizeof(RadiusRemoteServerEntry)))
  185. {
  186. // Zero out the new entry.
  187. entry = stats->rseRemoteServers + stats->dwNumRemoteServers;
  188. memset(entry, 0, sizeof(*entry));
  189. // Set the address.
  190. entry->dwAddress = address;
  191. // Update the number of servers ...
  192. ++(stats->dwNumRemoteServers);
  193. // ... and the number of bytes.
  194. nbyte += sizeof(RadiusRemoteServerEntry);
  195. }
  196. }
  197. unlock();
  198. }
  199. return entry;
  200. }
  201. //////////
  202. // Array that maps a (RadiusMIB, RadiusEvent) pair to a RemoteServer counter
  203. // offset.
  204. //////////
  205. LONG counterOffset[][2] =
  206. {
  207. // eventNone
  208. { -1, -1 },
  209. // eventInvalidAddress
  210. { radiusAuthClientInvalidAddresses, radiusAccClientInvalidAddresses },
  211. // eventAccessRequest
  212. { radiusAuthClientAccessRequests, -1 },
  213. // eventAccessAccept
  214. { radiusAuthClientAccessAccepts, -1 },
  215. // eventAccessReject
  216. { radiusAuthClientAccessRejects, -1 },
  217. // eventAccessChallenge
  218. { radiusAuthClientAccessChallenges, -1 },
  219. // eventAccountingRequest
  220. { -1, radiusAccClientRequests },
  221. // eventAccountingResponse
  222. { -1, radiusAccClientResponses },
  223. // eventMalformedPacket
  224. { radiusAuthClientMalformedAccessResponses, radiusAccClientResponses },
  225. // eventBadAuthenticator
  226. { radiusAuthClientBadAuthenticators, radiusAccClientBadAuthenticators },
  227. // eventBadSignature
  228. { radiusAuthClientBadAuthenticators, radiusAccClientBadAuthenticators },
  229. // eventMissingSignature
  230. { radiusAuthClientBadAuthenticators, radiusAccClientBadAuthenticators },
  231. // eventTimeout
  232. { radiusAuthClientTimeouts, radiusAccClientTimeouts },
  233. // eventUnknownType
  234. { radiusAuthClientUnknownTypes, radiusAccClientUnknownTypes },
  235. // eventUnexpectedResponse
  236. { radiusAuthClientPacketsDropped, radiusAccClientPacketsDropped },
  237. // eventLateResponse
  238. { radiusAuthClientPacketsDropped, radiusAccClientPacketsDropped },
  239. // eventRoundTrip
  240. { radiusAuthClientRoundTripTime, radiusAccClientRoundTripTime },
  241. // eventSendError
  242. { -1, -1 },
  243. // eventReceiveError
  244. { -1, -1 },
  245. // eventServerAvailable
  246. { -1, -1 },
  247. // eventServerUnavailable
  248. { -1, -1 }
  249. };
  250. void ProxyCounters::updateCounters(
  251. RadiusPortType port,
  252. RadiusEventType event,
  253. RadiusRemoteServerEntry* server,
  254. ULONG data
  255. ) throw ()
  256. {
  257. // Get the counter offset. If it's negative, then this event doesn't effect
  258. // any counters.
  259. LONG offset = counterOffset[event][port];
  260. if (offset < 0) { return; }
  261. if (event == eventInvalidAddress)
  262. {
  263. InterlockedIncrement((PLONG)stats->peProxy.dwCounters + offset);
  264. }
  265. else if (server)
  266. {
  267. if (event == eventRoundTrip)
  268. {
  269. server->dwCounters[offset] = data;
  270. }
  271. else
  272. {
  273. InterlockedIncrement((PLONG)server->dwCounters + offset);
  274. }
  275. }
  276. }
  277. RadiusRemoteServerEntry* ProxyCounters::findRemoteServer(
  278. ULONG address
  279. ) throw ()
  280. {
  281. for (DWORD i = 0; i < stats->dwNumRemoteServers; ++i)
  282. {
  283. if (stats->rseRemoteServers[i].dwAddress == address)
  284. {
  285. return stats->rseRemoteServers + i;
  286. }
  287. }
  288. return NULL;
  289. }