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.

337 lines
9.1 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: A R C . C P P
  7. //
  8. // Contents: Notification support for active ras connections.
  9. //
  10. // Notes: This module maintains a global array of active RAS connections.
  11. // This array is initialized with a call to
  12. // HrArcEnsureCachedAndListening. A thread waits for
  13. // notifications that a RAS connection has either been connected
  14. // or disconnected. When this happens, the thread calls
  15. // ArcWaitCallback which updates the
  16. // global array. The thread gets its handle to wait on from
  17. // HrArcEnsureCachedAndListening. The thread is not implemented
  18. // here but rather a sytem-provide thread pool is used.
  19. //
  20. // Author: shaunco 7 Feb 1998
  21. //
  22. //----------------------------------------------------------------------------
  23. #include "pch.h"
  24. #pragma hdrstop
  25. #include "arc.h"
  26. #include "conman.h"
  27. #include "ncmisc.h"
  28. #include "ncras.h"
  29. #include "nmbase.h"
  30. #include <raserror.h>
  31. ASSERTDATA;
  32. // This is the global data representing active ras connections.
  33. //
  34. struct ACTIVE_RAS_CONNECTIONS
  35. {
  36. // This is set after calling ArcInitialize.
  37. //
  38. BOOL fInitialized;
  39. // This critical section protects reading and writing to members of
  40. // this structure.
  41. //
  42. CRITICAL_SECTION critsec;
  43. // This is the array and count of active ras connections.
  44. //
  45. RASCONN* aRasConn;
  46. DWORD cRasConn;
  47. // This is the event handle that is signled when a connection is
  48. // connected or disconnected.
  49. //
  50. HANDLE hEvent;
  51. // This is the wait handle returned from RtlRegisterWait.
  52. //
  53. HANDLE hWait;
  54. // This is set after the first call to HrArcEnsureCachedAndListening.
  55. //
  56. BOOL fCachedAndListening;
  57. };
  58. ACTIVE_RAS_CONNECTIONS g_Arc = { 0 };
  59. //+---------------------------------------------------------------------------
  60. //
  61. // Function: ArcInitialize
  62. //
  63. // Purpose: Initialize this module for use.
  64. //
  65. // Arguments:
  66. // (none)
  67. //
  68. // Returns: nothing
  69. //
  70. // Author: shaunco 7 Feb 1998
  71. //
  72. // Notes: This can only be called once. It must be called before
  73. // any other Arc* API can be called.
  74. //
  75. VOID
  76. ArcInitialize ()
  77. {
  78. Assert (!g_Arc.fInitialized);
  79. InitializeCriticalSection (&g_Arc.critsec);
  80. g_Arc.fInitialized = TRUE;
  81. }
  82. //+---------------------------------------------------------------------------
  83. //
  84. // Function: ArcUninitialize
  85. //
  86. // Purpose: Uninitialize this module.
  87. //
  88. // Arguments:
  89. // (none)
  90. //
  91. // Returns: nothing
  92. //
  93. // Author: shaunco 7 Feb 1998
  94. //
  95. // Notes: This can only be called once. It must be called after the
  96. // last call to any other Arc* API.
  97. //
  98. VOID
  99. ArcUninitialize ()
  100. {
  101. Assert (g_Arc.fInitialized);
  102. if (g_Arc.fCachedAndListening)
  103. {
  104. CExceptionSafeLock EsLock (&g_Arc.critsec);
  105. if (g_Arc.hWait)
  106. {
  107. TraceTag (ttidWanCon, "ArcUninitialize: calling RtlDeregisterWait");
  108. RtlDeregisterWait (g_Arc.hWait);
  109. g_Arc.hWait = NULL;
  110. }
  111. TraceTag (ttidWanCon, "ArcUninitialize: closing event handle");
  112. CloseHandle (g_Arc.hEvent);
  113. g_Arc.hEvent = NULL;
  114. MemFree (g_Arc.aRasConn);
  115. g_Arc.aRasConn = NULL;
  116. g_Arc.cRasConn = 0;
  117. g_Arc.fCachedAndListening = FALSE;
  118. }
  119. // We can't delete the critical section unless we can guarantee
  120. // that no other API (like HrArcFindRasConnFromGuidId)
  121. // will be called. (This is assumed.)
  122. //
  123. DeleteCriticalSection (&g_Arc.critsec);
  124. g_Arc.fInitialized = FALSE;
  125. }
  126. //+---------------------------------------------------------------------------
  127. //
  128. // Function: ArcWaitCallback
  129. //
  130. // Purpose: Called by the RTL thread pool for this process when
  131. // g_Arc.hEvent is signaled. This event will be signaled by
  132. // the Rasman service when the state of an outgoing
  133. // connection changes.
  134. //
  135. // Arguments:
  136. // pvContext [in] Our user data. (Not used here.)
  137. // fTimeout [in] TRUE if we were called because of a timeout.
  138. //
  139. // Returns: nothing
  140. //
  141. // Author: shaunco 7 Feb 1998
  142. //
  143. // Notes: Be quick about this. We're being called on a thread provided
  144. // by the system.
  145. //
  146. VOID
  147. NTAPI
  148. ArcWaitCallback (
  149. PVOID pvContext,
  150. BOOLEAN fTimeout)
  151. {
  152. Assert (g_Arc.fInitialized);
  153. Assert (g_Arc.fCachedAndListening);
  154. // Let's be sure we only do work if the service state is still running.
  155. // If we have a stop pending for example, we don't need to do anything.
  156. //
  157. if (SERVICE_RUNNING != _Module.DwServiceStatus ())
  158. {
  159. TraceTag (ttidWanCon, "ArcWaitCallback called while service is not "
  160. "in SERVICE_RUNNING state. Ignoring.");
  161. return;
  162. }
  163. HRESULT hr = S_OK;
  164. // Lock scope
  165. {
  166. // Prevent other threads from reading the data we are about to update.
  167. //
  168. CExceptionSafeLock EsLock (&g_Arc.critsec);
  169. DWORD cRasConnOld = g_Arc.cRasConn;
  170. MemFree (g_Arc.aRasConn);
  171. hr = HrRasEnumAllActiveConnections (&g_Arc.aRasConn, &g_Arc.cRasConn);
  172. TraceTag (ttidWanCon,
  173. "ArcWaitCallback called: connection count: %u -> %u",
  174. cRasConnOld,
  175. g_Arc.cRasConn);
  176. }
  177. // Tell the connection manager to advise it's clients that a change
  178. // occured and re-enumeration is neccessary.
  179. //
  180. CConnectionManager::NotifyClientsOfChange ();
  181. TraceHr (ttidError, FAL, hr, FALSE, "ArcWaitCallback");
  182. }
  183. HRESULT
  184. HrArcEnsureCachedAndListening ()
  185. {
  186. Assert (g_Arc.fInitialized);
  187. if (g_Arc.fCachedAndListening)
  188. {
  189. return S_OK;
  190. }
  191. g_Arc.fCachedAndListening = TRUE;
  192. TraceTag (ttidWanCon, "Initializing active ras "
  193. "connections cache...");
  194. HRESULT hr = E_FAIL;
  195. // Prevent other threads from reading the data we are about to update.
  196. //
  197. CExceptionSafeLock EsLock (&g_Arc.critsec);
  198. // Create an auto-reset event and register it with
  199. // RasConnectionNotification.
  200. //
  201. g_Arc.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  202. if (g_Arc.hEvent)
  203. {
  204. // We want to register for state changes to all connection objects
  205. // so we pass INVALID_HANDLE_VALUE for the first parameter.
  206. //
  207. DWORD dwErr = RasConnectionNotification (
  208. reinterpret_cast<HRASCONN>(INVALID_HANDLE_VALUE),
  209. g_Arc.hEvent,
  210. RASCN_Connection | RASCN_Disconnection |
  211. RASCN_BandwidthAdded | RASCN_BandwidthRemoved);
  212. hr = HRESULT_FROM_WIN32 (dwErr);
  213. TraceHr (ttidError, FAL, hr, FALSE, "RasConnectionNotification", hr);
  214. if (SUCCEEDED(hr))
  215. {
  216. // Initialize the array of active RAS connections before
  217. // registering for a wait callack on the event.
  218. //
  219. MemFree (g_Arc.aRasConn);
  220. hr = HrRasEnumAllActiveConnections (&g_Arc.aRasConn,
  221. &g_Arc.cRasConn);
  222. if (SUCCEEDED(hr))
  223. {
  224. NTSTATUS status;
  225. status = RtlRegisterWait (&g_Arc.hWait, g_Arc.hEvent,
  226. ArcWaitCallback, NULL, INFINITE, WT_EXECUTEDEFAULT);
  227. if (!NT_SUCCESS(status))
  228. {
  229. hr = HRESULT_FROM_NT (status);
  230. TraceHr (ttidError, FAL, hr, FALSE,
  231. "RtlRegisterWait", hr);
  232. }
  233. else
  234. {
  235. TraceTag (ttidWanCon, "Cached and listening for "
  236. "ras connection state changes...");
  237. hr = S_OK;
  238. }
  239. if (FAILED(hr))
  240. {
  241. MemFree (g_Arc.aRasConn);
  242. g_Arc.aRasConn = NULL;
  243. }
  244. }
  245. }
  246. if (FAILED(hr))
  247. {
  248. CloseHandle (g_Arc.hEvent);
  249. g_Arc.hEvent = NULL;
  250. }
  251. }
  252. else
  253. {
  254. hr = HrFromLastWin32Error ();
  255. TraceHr (ttidError, FAL, hr, FALSE, "CreateEvent", hr);
  256. }
  257. TraceHr (ttidError, FAL, hr, FALSE, "HrArcEnsureCachedAndListening");
  258. return hr;
  259. }
  260. HRESULT
  261. HrArcFindRasConnFromGuidId (
  262. const GUID* pguidId,
  263. HRASCONN* phRasConn)
  264. {
  265. Assert (g_Arc.fInitialized);
  266. Assert (pguidId);
  267. Assert (phRasConn);
  268. // Initialize the output parameter.
  269. //
  270. *phRasConn = NULL;
  271. HRESULT hr = S_FALSE;
  272. // Prevent the update thread from updating the data
  273. // until we are done reading it.
  274. //
  275. CExceptionSafeLock EsLock (&g_Arc.critsec);
  276. for (DWORD dwIndex = 0; dwIndex < g_Arc.cRasConn; dwIndex++)
  277. {
  278. if (*pguidId == g_Arc.aRasConn[dwIndex].guidEntry)
  279. {
  280. *phRasConn = g_Arc.aRasConn[dwIndex].hrasconn;
  281. hr = S_OK;
  282. break;
  283. }
  284. }
  285. TraceHr (ttidError, FAL, hr, (S_FALSE == hr),
  286. "HrArcFindRasConnFromGuidId");
  287. return hr;
  288. }