Leaked source code of windows server 2003
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.

1460 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997-2001.
  5. //
  6. // File: E V E N T . C P P
  7. //
  8. // Contents: Interface between external events that effect connections.
  9. //
  10. // Notes:
  11. //
  12. // Author: shaunco 21 Aug 1998
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <winsock2.h>
  18. #include <mswsock.h>
  19. #include <iphlpapi.h>
  20. #include "nmbase.h"
  21. #include "ncnetcon.h"
  22. #include "conman.h"
  23. #include <cmdefs.h>
  24. #include "cmutil.h"
  25. #include "eventq.h"
  26. #include <userenv.h>
  27. #include <userenvp.h>
  28. #include "ncperms.h"
  29. #include <ras.h>
  30. #include <raserror.h>
  31. #include <ncstl.h>
  32. #include <algorithm>
  33. #include <lancmn.h>
  34. #include <ncreg.h>
  35. #include "gpnla.h"
  36. #include "cobase.h"
  37. #include <mprapi.h>
  38. #include <rasapip.h>
  39. #include "ncras.h"
  40. #include "wzcsvc.h"
  41. #include "cmdirect.h"
  42. // This LONG is incremented every time we get a notification that
  43. // a RAS phonebook entry has been modified. It is reset to zero
  44. // when the service is started. Wrap-around does not matter. It's
  45. // purpose is to let a RAS connection object know if it's cache should
  46. // be re-populated with current information.
  47. //
  48. LONG g_lRasEntryModifiedVersionEra;
  49. LONG g_cInRefreshAll;
  50. const LONG MAX_IN_REFRESH_ALL = 5;
  51. CEventQueue* g_pEventQueue = NULL;
  52. BOOL g_fDispatchEvents = FALSE;
  53. HANDLE g_hEventWait = NULL;
  54. HANDLE g_hEventThread = NULL;
  55. HANDLE g_hQuery = NULL;
  56. BOOL g_fHandleIncomingEvents = FALSE;
  57. CGroupPolicyNetworkLocationAwareness* g_pGPNLA = NULL;
  58. //+---------------------------------------------------------------------------
  59. //
  60. // Function: FreeConmanEvent
  61. //
  62. // Purpose: Free the memory associated with a CONMAN_EVENT structure.
  63. //
  64. // Arguments:
  65. // pEvent [in] The structure to free.
  66. //
  67. // Returns: nothing
  68. //
  69. // Author: shaunco 21 Aug 1998
  70. //
  71. // Notes:
  72. //
  73. inline
  74. VOID
  75. FreeConmanEvent (
  76. IN TAKEOWNERSHIP CONMAN_EVENT* pEvent) throw()
  77. {
  78. TraceFileFunc(ttidEvents);
  79. if (pEvent)
  80. {
  81. if (((CONNECTION_ADDED == pEvent->Type) ||
  82. (CONNECTION_MODIFIED == pEvent->Type)))
  83. {
  84. HRESULT hr = HrFreeNetConProperties2(pEvent->pPropsEx);
  85. TraceError("HrFreeNetConProperties2", hr);
  86. }
  87. if (CONNECTION_BALLOON_POPUP == pEvent->Type)
  88. {
  89. SysFreeString(pEvent->szCookie);
  90. SysFreeString(pEvent->szBalloonText);
  91. }
  92. MemFree(pEvent);
  93. }
  94. }
  95. //+---------------------------------------------------------------------------
  96. //
  97. // Function: RasEventWorkItem
  98. //
  99. // Purpose: The LPTHREAD_START_ROUTINE passed to QueueUserWorkItem to
  100. // handle the work of notifying connection manager clients
  101. // of the event.
  102. //
  103. // Arguments:
  104. // pvContext [in] A pointer to a CONMAN_EVENT structure.
  105. //
  106. // Returns: NOERROR
  107. //
  108. // Author: sjkhan 21 Mar 2001
  109. //
  110. // Notes: This function calls Ras on a different thread than where the
  111. // event came from so as not to cause a deadlock in Ras.
  112. // This call owns pvContext and frees it.
  113. //
  114. DWORD
  115. WINAPI
  116. RasEventWorkItem (
  117. IN TAKEOWNERSHIP CONMAN_EVENT* pEvent
  118. )
  119. {
  120. TraceFileFunc(ttidEvents);
  121. BOOL fNotify;
  122. Assert (pEvent);
  123. if (SERVICE_RUNNING == _Module.DwServiceStatus ())
  124. {
  125. fNotify = TRUE;
  126. if (fNotify)
  127. {
  128. HRESULT hr = S_OK;
  129. RASENUMENTRYDETAILS Details;
  130. if (CONNECTION_ADDED == pEvent->Type || CONNECTION_MODIFIED == pEvent->Type)
  131. {
  132. // Clear out the details passed in from RAS and query RAS for the latest info.
  133. Details = pEvent->Details;
  134. ZeroMemory(&pEvent->Details, sizeof(RASENUMENTRYDETAILS));
  135. if (CONNECTION_ADDED == pEvent->Type)
  136. {
  137. hr = HrGetRasConnectionProperties(&Details, &(pEvent->pPropsEx));
  138. }
  139. else if (CONNECTION_MODIFIED == pEvent->Type)
  140. {
  141. hr = HrGetRasConnectionProperties(&Details, &(pEvent->pPropsEx));
  142. TraceTag(ttidEvents, "Is Default Connection: %s", (NCCF_DEFAULT == (pEvent->pPropsEx->dwCharacter & NCCF_DEFAULT)) ? "Yes" : "No");
  143. TraceTag(ttidEvents, "Should be Default Connection: %s", (Details.dwFlagsPriv & REED_F_Default) ? "Yes" : "No");
  144. }
  145. }
  146. if (SUCCEEDED(hr))
  147. {
  148. CConnectionManager::NotifyClientsOfEvent (pEvent);
  149. }
  150. }
  151. }
  152. FreeConmanEvent(pEvent);
  153. return NOERROR;
  154. }
  155. //+---------------------------------------------------------------------------
  156. //
  157. // Function: LanEventWorkItem
  158. //
  159. // Purpose: The LPTHREAD_START_ROUTINE passed to QueueUserWorkItem to
  160. // handle the work of notifying connection manager clients
  161. // of the event.
  162. //
  163. // Arguments:
  164. // pvContext [in] A pointer to a CONMAN_EVENT structure.
  165. //
  166. // Returns: NOERROR
  167. //
  168. // Author: deonb 15 May 2001
  169. //
  170. // Notes: This function retreives a more up to do status from the NIC
  171. // and sends it to netshell
  172. //
  173. DWORD
  174. WINAPI
  175. LanEventWorkItem (
  176. IN TAKEOWNERSHIP CONMAN_EVENT* pEvent
  177. )
  178. {
  179. TraceFileFunc(ttidEvents);
  180. BOOL fNotify;
  181. Assert (pEvent);
  182. Assert(CONMAN_LAN== pEvent->ConnectionManager);
  183. HRESULT hr = S_OK;
  184. RASENUMENTRYDETAILS Details;
  185. TraceTag(ttidEvents, "Refreshing connection status");
  186. GUID gdLanGuid = GUID_NULL;
  187. if ((CONNECTION_ADDED == pEvent->Type) || (CONNECTION_MODIFIED == pEvent->Type))
  188. {
  189. gdLanGuid = pEvent->pPropsEx->guidId;
  190. }
  191. if ((CONNECTION_STATUS_CHANGE == pEvent->Type) || (CONNECTION_ADDRESS_CHANGE == pEvent->Type) || (CONNECTION_DELETED == pEvent->Type))
  192. {
  193. gdLanGuid = pEvent->guidId;
  194. }
  195. Assert(GUID_NULL != gdLanGuid);
  196. if (GUID_NULL == gdLanGuid)
  197. {
  198. return E_INVALIDARG;
  199. }
  200. #ifdef DBG
  201. NETCON_STATUS ncsPrior;
  202. #endif
  203. NETCON_STATUS ncs;
  204. hr = HrGetPnpDeviceStatus(&gdLanGuid, &ncs);
  205. if (SUCCEEDED(hr))
  206. {
  207. // Get additional Status information from 802.1X
  208. //
  209. if ((NCS_CONNECTED == ncs)
  210. || (NCS_INVALID_ADDRESS == ncs)
  211. || (NCS_MEDIA_DISCONNECTED == ncs))
  212. {
  213. NETCON_STATUS ncsWZC = ncs;
  214. HRESULT hrT = WZCQueryGUIDNCSState(&gdLanGuid, &ncsWZC);
  215. if (S_OK == hrT)
  216. {
  217. ncs = ncsWZC;
  218. }
  219. TraceHr(ttidError, FAL, hrT, (S_FALSE == hrT), "LanEventWorkItem error in WZCQueryGUIDNCSState");
  220. }
  221. if ( (CONNECTION_ADDED == pEvent->Type) || (CONNECTION_MODIFIED == pEvent->Type))
  222. {
  223. #ifdef DBG
  224. ncsPrior = pEvent->pPropsEx->ncStatus;
  225. #endif
  226. pEvent->pPropsEx->ncStatus = ncs;
  227. }
  228. if (CONNECTION_STATUS_CHANGE == pEvent->Type)
  229. {
  230. #ifdef DBG
  231. ncsPrior = pEvent->Status;
  232. #endif
  233. if ( (NCS_HARDWARE_NOT_PRESENT == ncs) ||
  234. (NCS_HARDWARE_MALFUNCTION == ncs) )
  235. {
  236. pEvent->Type = CONNECTION_DELETED;
  237. TraceTag(ttidEvents, "LanEventWorkItem changed EventType to CONNECTION_DELETED");
  238. }
  239. else
  240. {
  241. pEvent->Status = ncs;
  242. }
  243. }
  244. }
  245. #ifdef DBG
  246. if (ncsPrior != ncs)
  247. {
  248. TraceTag(ttidEvents, "LanEventWorkItem overruled status: %s to %s", DbgNcs(ncsPrior), DbgNcs(ncs));
  249. }
  250. #endif
  251. CConnectionManager::NotifyClientsOfEvent (pEvent);
  252. FreeConmanEvent(pEvent);
  253. TraceHr(ttidError, FAL, hr, FALSE, "LanEventWorkItem");
  254. return hr;
  255. }
  256. //+---------------------------------------------------------------------------
  257. //
  258. // Function: IncomingEventWorkItem
  259. //
  260. // Purpose: The LPTHREAD_START_ROUTINE passed to QueueUserWorkItem to
  261. // handle the work of notifying connection manager clients
  262. // of the event.
  263. //
  264. // Arguments:
  265. // pvContext [in] A pointer to a CONMAN_EVENT structure.
  266. //
  267. // Returns: NOERROR
  268. //
  269. // Author: sjkhan 21 Mar 2001
  270. //
  271. // Notes: This function calls Ras on a different thread than where the
  272. // event came from so as not to cause a deadlock in Ras.
  273. // This call owns pvContext and frees it.
  274. //
  275. DWORD
  276. WINAPI
  277. IncomingEventWorkItem (
  278. IN TAKEOWNERSHIP CONMAN_EVENT* pEvent
  279. )
  280. {
  281. TraceFileFunc(ttidEvents);
  282. BOOL fNotify;
  283. Assert (pEvent);
  284. if (SERVICE_RUNNING == _Module.DwServiceStatus ())
  285. {
  286. fNotify = TRUE;
  287. if (fNotify)
  288. {
  289. HRESULT hr = S_OK;
  290. if (CONNECTION_ADDED == pEvent->Type)
  291. {
  292. GUID guidId;
  293. guidId = pEvent->guidId; // We need to store this because CONMAN_EVENT is a union and pProps occupies the same space as guidId.
  294. pEvent->guidId = GUID_NULL; // We don't need this anymore so it's a good idea to clean it up, as pEvent is a union.
  295. hr = HrGetIncomingConnectionPropertiesEx(pEvent->hConnection, &guidId, pEvent->dwConnectionType, &pEvent->pPropsEx);
  296. }
  297. if (SUCCEEDED(hr))
  298. {
  299. CConnectionManager::NotifyClientsOfEvent (pEvent);
  300. }
  301. }
  302. }
  303. FreeConmanEvent(pEvent);
  304. return NOERROR;
  305. }
  306. //+---------------------------------------------------------------------------
  307. //
  308. // Function: ConmanEventWorkItem
  309. //
  310. // Purpose: The LPTHREAD_START_ROUTINE passed to QueueUserWorkItem to
  311. // handle the work of notifying connection manager clients
  312. // of the event.
  313. //
  314. // Arguments:
  315. // pvContext [in] A pointer to a CONMAN_EVENT structure.
  316. //
  317. // Returns: NOERROR
  318. //
  319. // Author: shaunco 21 Aug 1998
  320. //
  321. // Notes: Ownership of the CONMAN_EVENT structure is given to this
  322. // function. i.e. the structure is freed here.
  323. //
  324. DWORD
  325. WINAPI
  326. ConmanEventWorkItem (
  327. IN TAKEOWNERSHIP CONMAN_EVENT* pEvent
  328. )
  329. {
  330. TraceFileFunc(ttidEvents);
  331. BOOL fIsRefreshAll;
  332. BOOL fNotify;
  333. Assert (pEvent);
  334. if (SERVICE_RUNNING == _Module.DwServiceStatus ())
  335. {
  336. fIsRefreshAll = (REFRESH_ALL == pEvent->Type);
  337. fNotify = TRUE;
  338. if (fIsRefreshAll)
  339. {
  340. // We'll deliver this refresh-all notification only if another
  341. // thread is not already delivering one.
  342. //
  343. fNotify = (InterlockedIncrement (&g_cInRefreshAll) < MAX_IN_REFRESH_ALL);
  344. }
  345. if (fNotify)
  346. {
  347. CConnectionManager::NotifyClientsOfEvent (pEvent);
  348. }
  349. // Reset our global flag if we were the single thread allowed to
  350. // deliver a refresh-all notification.
  351. //
  352. if (fIsRefreshAll)
  353. {
  354. if (InterlockedDecrement (&g_cInRefreshAll) < 0)
  355. {
  356. AssertSz (FALSE, "Mismatched Interlocked Increment/Decrement?");
  357. g_cInRefreshAll = 0;
  358. }
  359. }
  360. }
  361. FreeConmanEvent (pEvent);
  362. return NOERROR;
  363. }
  364. //+---------------------------------------------------------------------------
  365. //
  366. // Function: LanEventNotify
  367. //
  368. // Purpose: To be called when a LAN adapter is added or removed.
  369. //
  370. // Arguments:
  371. // EventType [in] Type of the event
  372. // pConn [in] The INetConnection (only for CONNECTION_ADDED, CONNECTION_MODIFIED)
  373. // pszNewName [in] The name (for CONNECTION_RENAMED)
  374. // pguidConn [in] The GUID of the connection (for CONNECTION_RENAMED)
  375. //
  376. // Returns: nothing
  377. //
  378. // Author: shaunco 2 Sep 1998
  379. //
  380. // Notes: The easy thing is done a full refresh is queued for the
  381. // connection manager to notify its clients of.
  382. //
  383. VOID
  384. LanEventNotify (
  385. IN CONMAN_EVENTTYPE EventType,
  386. IN INetConnection* pConn,
  387. IN PCWSTR pszNewName,
  388. IN const GUID * pguidConn) throw()
  389. {
  390. TraceFileFunc(ttidEvents);
  391. // Let's be sure we only do work if the service state is still running.
  392. // If we have a stop pending for example, we don't need to do anything.
  393. //
  394. if (SERVICE_RUNNING != _Module.DwServiceStatus ())
  395. {
  396. return;
  397. }
  398. // If the connection manager has no active connection points registered,
  399. // we don't need to do anything.
  400. //
  401. if (!CConnectionManager::FHasActiveConnectionPoints ())
  402. {
  403. return;
  404. }
  405. if ((REFRESH_ALL == EventType) && (g_cInRefreshAll >= MAX_IN_REFRESH_ALL))
  406. {
  407. return;
  408. }
  409. // Allocate a CONMAN_EVENT structure and initialize it from the
  410. // RASEVENT information.
  411. //
  412. CONMAN_EVENT* pEvent = (CONMAN_EVENT*)MemAlloc (sizeof(CONMAN_EVENT));
  413. if (!pEvent)
  414. {
  415. TraceTag (ttidEvents,
  416. "Failed to allocate a new work item in LanEventNotify.");
  417. return;
  418. }
  419. ZeroMemory (pEvent, sizeof(CONMAN_EVENT));
  420. pEvent->ConnectionManager = CONMAN_LAN;
  421. pEvent->Type = EventType;
  422. BOOL fFreeEvent = TRUE;
  423. HRESULT hr = S_OK;
  424. if (pConn)
  425. {
  426. // pEvent->pProps is only valid for added and modified events.
  427. // So, we don't want to be getting properties for any other event.
  428. //
  429. AssertSz (
  430. (CONNECTION_ADDED == EventType) ||
  431. (CONNECTION_MODIFIED == EventType),
  432. "Why is pConn being passed for this event type?");
  433. hr = HrGetPropertiesExFromINetConnection(pConn, &pEvent->pPropsEx);
  434. }
  435. AssertSz(FImplies(EventType == CONNECTION_RENAMED, FIff(pszNewName,
  436. !pConn)),
  437. "szwNewName && pConn cannot be NULL or non-NULL at "
  438. "the same time!");
  439. AssertSz(FIff(pszNewName, pguidConn), "szwNewName & pguidConn must both "
  440. "be NULL or non-NULL");
  441. if (EventType == CONNECTION_RENAMED)
  442. {
  443. AssertSz(pszNewName, "Rename event requires szwNewName to be "
  444. "non-NULL");
  445. AssertSz(pguidConn, "Rename event requires pguidConn to be "
  446. "non-NULL");
  447. // Copy in the right info into the event struct
  448. //
  449. pEvent->guidId = *pguidConn;
  450. lstrcpynW(pEvent->szNewName, pszNewName, celems(pEvent->szNewName));
  451. }
  452. if (S_OK == hr)
  453. {
  454. TraceTag (ttidEvents,
  455. "LanEventNotify: Queuing ConmanEventWorkItem (Type=%s)...",
  456. DbgEvents(pEvent->Type));
  457. // Queue a worker to deliver the event to the clients of the
  458. // connection manager with registered connection points.
  459. // We pass ownership of the structure to the worker thread which
  460. // will free it. (Therefore, we don't want to free it.)
  461. //
  462. if (QueueUserWorkItemInThread (ConmanEventWorkItem,
  463. pEvent, EVENTMGR_CONMAN))
  464. {
  465. fFreeEvent = FALSE;
  466. }
  467. else
  468. {
  469. TraceTag (ttidEvents,
  470. "QueueUserWorkItem failed with error %d in LanEventNotify.",
  471. GetLastError ());
  472. }
  473. }
  474. if (fFreeEvent)
  475. {
  476. FreeConmanEvent (pEvent);
  477. }
  478. }
  479. //+---------------------------------------------------------------------------
  480. //
  481. // Function: FIsIgnorableCMEvent
  482. //
  483. // Purpose: Determine whether an event is an ignorable CM event, such
  484. // as those that are adds/removes from a temporary CM connection
  485. // (used by CM VPN connections to double-dial). We don't want
  486. // clients to react to these events.
  487. //
  488. // Arguments:
  489. // pRasEvent [in] pointer to a RASEVENT structure describing the event.
  490. //
  491. // Returns:
  492. //
  493. // Author: jeffspr 15 Jan 1999
  494. //
  495. // Notes:
  496. //
  497. BOOL FIsIgnorableCMEvent(IN const RASEVENT* pRasEvent) throw()
  498. {
  499. TraceFileFunc(ttidEvents);
  500. BOOL fReturn = FALSE;
  501. WCHAR szFileName[MAX_PATH];
  502. Assert(pRasEvent);
  503. // Split the filename out of the path
  504. //
  505. _wsplitpath(pRasEvent->Details.szPhonebookPath, NULL, NULL,
  506. szFileName, NULL);
  507. // Compare that file name with the filter prefix to see if we
  508. // should throw this event away
  509. //
  510. if (_wcsnicmp(CM_PBK_FILTER_PREFIX, szFileName,
  511. wcslen(CM_PBK_FILTER_PREFIX)) == 0)
  512. {
  513. fReturn = TRUE;
  514. }
  515. return fReturn;
  516. }
  517. HRESULT HrGetRasConnectionProperties(
  518. IN const RASENUMENTRYDETAILS* pDetails,
  519. OUT NETCON_PROPERTIES_EX** ppPropsEx)
  520. {
  521. TraceFileFunc(ttidEvents);
  522. HRESULT hr = S_OK;
  523. INetConnection* pConn;
  524. Assert(ppPropsEx);
  525. hr = CMDIRECT(DIALUP, CreateInstanceFromDetails)(
  526. pDetails,
  527. IID_INetConnection,
  528. reinterpret_cast<VOID**>(&pConn));
  529. if (SUCCEEDED(hr))
  530. {
  531. hr = HrGetPropertiesExFromINetConnection(pConn, ppPropsEx);
  532. ReleaseObj (pConn);
  533. }
  534. return hr;
  535. }
  536. HRESULT HrGetIncomingConnectionPropertiesEx(
  537. IN const HANDLE hRasConn,
  538. IN const GUID* pguidId,
  539. IN const DWORD dwType,
  540. OUT NETCON_PROPERTIES_EX** ppPropsEx)
  541. {
  542. TraceFileFunc(ttidEvents);
  543. HRESULT hr = S_OK;
  544. DWORD dwResult = 0;
  545. RAS_SERVER_HANDLE hRasServer = NULL;
  546. RAS_CONNECTION_2* pRasConnection = NULL;
  547. if (NULL == hRasConn)
  548. {
  549. return E_INVALIDARG;
  550. }
  551. if (!ppPropsEx)
  552. {
  553. return E_POINTER;
  554. }
  555. *ppPropsEx = NULL;
  556. dwResult = MprAdminServerConnect(NULL, &hRasServer);
  557. if (NO_ERROR == dwResult)
  558. {
  559. dwResult = MprAdminConnectionGetInfo(hRasServer, 2, hRasConn, reinterpret_cast<LPBYTE*>(&pRasConnection));
  560. if (NO_ERROR == dwResult)
  561. {
  562. DWORD dwRead = 0;
  563. DWORD dwTot = 0;
  564. RAS_PORT_0* pPort = NULL;
  565. dwResult = MprAdminPortEnum(hRasServer,
  566. 0,
  567. hRasConn,
  568. (LPBYTE*)&pPort,
  569. sizeof(RAS_PORT_0) * 2,
  570. &dwRead,
  571. &dwTot,
  572. NULL);
  573. if (NO_ERROR == dwResult)
  574. {
  575. CComPtr<INetConnection> pConn;
  576. hr = CMDIRECT(INBOUND, CreateInstance)(FALSE,
  577. hRasConn,
  578. pRasConnection->wszUserName,
  579. pPort->wszDeviceName,
  580. dwType,
  581. pguidId,
  582. IID_INetConnection,
  583. reinterpret_cast<LPVOID*>(&pConn));
  584. if (SUCCEEDED(hr))
  585. {
  586. hr = HrGetPropertiesExFromINetConnection(pConn, ppPropsEx);
  587. (*ppPropsEx)->ncStatus = NCS_CONNECTED;
  588. }
  589. MprAdminBufferFree(reinterpret_cast<LPVOID>(pPort));
  590. }
  591. MprAdminBufferFree(pRasConnection);
  592. }
  593. MprAdminServerDisconnect(hRasServer);
  594. }
  595. if (NO_ERROR != dwResult)
  596. {
  597. hr = HRESULT_FROM_WIN32(dwResult);
  598. }
  599. return hr;
  600. }
  601. //+---------------------------------------------------------------------------
  602. //
  603. // Function: RasEventNotify
  604. //
  605. // Purpose: Private export used by Rasman service to notify the
  606. // Netman service of RAS events which may effect connections.
  607. //
  608. // Arguments:
  609. // pRasEvent [in] pointer to a RASEVENT structure describing the event.
  610. //
  611. // Returns: nothing
  612. //
  613. // Author: shaunco 21 Aug 1998
  614. //
  615. // Notes:
  616. //
  617. VOID
  618. APIENTRY
  619. RasEventNotify (
  620. const RASEVENT* pRasEvent) /* throw() */
  621. {
  622. TraceFileFunc(ttidEvents);
  623. NETCON_STATUS ncs;
  624. BOOL fMatchedStatus = TRUE;
  625. Assert (pRasEvent);
  626. TraceTag (ttidEvents,
  627. "RasEventNotify: Recieved RAS event (Type=%d)...",
  628. pRasEvent->Type);
  629. // Let's be sure we only do work if the service state is still running.
  630. // If we have a stop pending for example, we don't need to do anything.
  631. //
  632. if (SERVICE_RUNNING != _Module.DwServiceStatus ())
  633. {
  634. return;
  635. }
  636. // Map the ras type to the conman type
  637. //
  638. switch(pRasEvent->Type)
  639. {
  640. case ENTRY_CONNECTED:
  641. ncs = NCS_CONNECTED;
  642. break;
  643. case ENTRY_CONNECTING:
  644. ncs = NCS_CONNECTING;
  645. break;
  646. case ENTRY_DISCONNECTING:
  647. ncs = NCS_DISCONNECTING;
  648. break;
  649. case ENTRY_DISCONNECTED:
  650. ncs = NCS_DISCONNECTED;
  651. break;
  652. default:
  653. fMatchedStatus = FALSE;
  654. }
  655. // Remember any Connection Manager connectoids and ras events
  656. // For Ras Connecting is Disconnected so we have to memorize the
  657. // real state of the connectoid. /*&& FIsIgnorableCMEvent(pRasEvent)*/
  658. //
  659. if( fMatchedStatus )
  660. {
  661. // Save the connection in a list
  662. //
  663. CCMUtil::Instance().SetEntry(pRasEvent->Details.guidId, pRasEvent->Details.szEntryName,ncs);
  664. }
  665. // If the connection manager has no active connection points registered,
  666. // we don't need to do anything.
  667. //
  668. if (!CConnectionManager::FHasActiveConnectionPoints ())
  669. {
  670. return;
  671. }
  672. // Windows XP Bug 336787.
  673. // sjkhan
  674. // We're checking to see if we should be firing events when the RemoteAccess Service
  675. // starts. We call the same API that we do when checking whether or not to show the
  676. // config connection, and we're then able to determine whether or not we should fire
  677. // the incoming events. Since we get notified of the service stopping and starting,
  678. // we'll always know when we should or should not fire IncomingEvents. This reduces
  679. // the call overhead to O(1), and since we exit here if we're not supposed to fire
  680. // events, we don't even have to allocate and then free the pEvent memory.
  681. //
  682. if (((INCOMING_CONNECTED == pRasEvent->Type) ||
  683. (INCOMING_DISCONNECTED == pRasEvent->Type)) &&
  684. !g_fHandleIncomingEvents)
  685. {
  686. return;
  687. }
  688. if ((ENTRY_ADDED == pRasEvent->Type) ||
  689. (ENTRY_DELETED == pRasEvent->Type))
  690. {
  691. // Filter out CM temporary phonebook events
  692. //
  693. if (FIsIgnorableCMEvent(pRasEvent))
  694. {
  695. TraceTag(ttidEvents, "Filtering ignorable CM event in RasEventNotify");
  696. return;
  697. }
  698. }
  699. // Allocate a CONMAN_EVENT structure and initialize it from the
  700. // RASEVENT information.
  701. //
  702. CONMAN_EVENT* pEvent = (CONMAN_EVENT*)MemAlloc (sizeof(CONMAN_EVENT));
  703. if (!pEvent)
  704. {
  705. TraceTag (ttidEvents,
  706. "Failed to allocate a new work item in RasEventNotify.");
  707. return;
  708. }
  709. ZeroMemory (pEvent, sizeof(CONMAN_EVENT));
  710. pEvent->ConnectionManager = CONMAN_RAS;
  711. BOOL fFreeEvent = TRUE;
  712. HRESULT hr = S_OK;
  713. switch (pRasEvent->Type)
  714. {
  715. case ENTRY_ADDED:
  716. pEvent->Type = CONNECTION_ADDED;
  717. pEvent->Details = pRasEvent->Details;
  718. TraceTag(ttidEvents, "Path: %S", pRasEvent->Details.szPhonebookPath);
  719. break;
  720. case ENTRY_DELETED:
  721. pEvent->Type = CONNECTION_DELETED;
  722. pEvent->guidId = pRasEvent->guidId;
  723. break;
  724. case ENTRY_MODIFIED:
  725. pEvent->Type = CONNECTION_MODIFIED;
  726. pEvent->Details = pRasEvent->Details;
  727. InterlockedIncrement(&g_lRasEntryModifiedVersionEra);
  728. break;
  729. case ENTRY_RENAMED:
  730. pEvent->Type = CONNECTION_RENAMED;
  731. pEvent->guidId = pRasEvent->guidId;
  732. lstrcpynW (
  733. pEvent->szNewName,
  734. pRasEvent->pszwNewName,
  735. celems(pEvent->szNewName) );
  736. InterlockedIncrement(&g_lRasEntryModifiedVersionEra);
  737. break;
  738. case ENTRY_AUTODIAL:
  739. pEvent->Type = CONNECTION_MODIFIED;
  740. pEvent->Details = pRasEvent->Details;
  741. InterlockedIncrement(&g_lRasEntryModifiedVersionEra);
  742. break;
  743. case ENTRY_CONNECTED:
  744. pEvent->Type = CONNECTION_STATUS_CHANGE;
  745. pEvent->guidId = pRasEvent->Details.guidId;
  746. pEvent->Status = NCS_CONNECTED;
  747. break;
  748. case ENTRY_CONNECTING:
  749. pEvent->Type = CONNECTION_STATUS_CHANGE;
  750. pEvent->guidId = pRasEvent->Details.guidId;
  751. pEvent->Status = NCS_CONNECTING;
  752. break;
  753. case ENTRY_DISCONNECTING:
  754. pEvent->Type = CONNECTION_STATUS_CHANGE;
  755. pEvent->guidId = pRasEvent->Details.guidId;
  756. pEvent->Status = NCS_DISCONNECTING;
  757. break;
  758. case ENTRY_DISCONNECTED:
  759. pEvent->Type = CONNECTION_STATUS_CHANGE;
  760. pEvent->guidId = pRasEvent->Details.guidId;
  761. pEvent->Status = NCS_DISCONNECTED;
  762. break;
  763. case INCOMING_CONNECTED:
  764. pEvent->ConnectionManager = CONMAN_INCOMING;
  765. pEvent->hConnection = pRasEvent->hConnection;
  766. pEvent->guidId = pRasEvent->guidId;
  767. pEvent->dwConnectionType = RasSrvTypeFromRasDeviceType(pRasEvent->rDeviceType);
  768. pEvent->Type = CONNECTION_ADDED;
  769. break;
  770. case INCOMING_DISCONNECTED:
  771. pEvent->ConnectionManager = CONMAN_INCOMING;
  772. pEvent->guidId = pRasEvent->guidId;
  773. pEvent->Type = CONNECTION_DELETED;
  774. break;
  775. case SERVICE_EVENT:
  776. if (REMOTEACCESS == pRasEvent->Service)
  777. {
  778. DWORD dwErr;
  779. pEvent->ConnectionManager = CONMAN_INCOMING;
  780. pEvent->Type = REFRESH_ALL;
  781. // Check to see if we should handle incoming events.
  782. dwErr = RasSrvAllowConnectionsConfig(&g_fHandleIncomingEvents);
  783. TraceError ("RasSrvIsConnectionConnected", HRESULT_FROM_WIN32(dwErr));
  784. }
  785. else if (RAS_SERVICE_STARTED == pRasEvent->Event)
  786. {
  787. _Module.ReferenceRasman(REF_REFERENCE);
  788. hr = S_FALSE;
  789. }
  790. else
  791. {
  792. // skip queueing the workitem
  793. hr = S_FALSE;
  794. }
  795. break;
  796. case ENTRY_BANDWIDTH_ADDED:
  797. case ENTRY_BANDWIDTH_REMOVED:
  798. pEvent->Type = CONNECTION_BANDWIDTH_CHANGE;
  799. pEvent->guidId = pRasEvent->guidId;
  800. break;
  801. case DEVICE_ADDED:
  802. case DEVICE_REMOVED:
  803. pEvent->Type = REFRESH_ALL;
  804. break;
  805. default:
  806. // skip queueing the workitem
  807. AssertSz (FALSE, "Invalid Type specified in pRasEvent");
  808. hr = S_FALSE;
  809. break;
  810. }
  811. if (S_OK == hr)
  812. {
  813. if (CONMAN_RAS == pEvent->ConnectionManager)
  814. {
  815. TraceTag (ttidEvents,
  816. "RasEventNotify: Queueing RasEventWorkItem (Type=%s)...",
  817. DbgEvents(pEvent->Type));
  818. // Queue the event to be delivered the event to the clients of the
  819. // connection manager with registered connection points.
  820. // We pass ownership of the structure to the worker thread which
  821. // will free it. (Therefore, we don't want to free it.)
  822. //
  823. if (QueueUserWorkItemInThread (RasEventWorkItem,
  824. pEvent, EVENTMGR_CONMAN))
  825. {
  826. fFreeEvent = FALSE;
  827. }
  828. else
  829. {
  830. TraceTag (ttidEvents,
  831. "QueueUserWorkItem failed with error %d in RasEventNotify.",
  832. GetLastError ());
  833. }
  834. }
  835. else if (CONMAN_INCOMING == pEvent->ConnectionManager)
  836. {
  837. TraceTag (ttidEvents,
  838. "RasEventNotify: Queueing IncomingEventWorkItem (Type=%s)...",
  839. DbgEvents(pEvent->Type));
  840. // Queue the event to be delivered the event to the clients of the
  841. // connection manager with registered connection points.
  842. // We pass ownership of the structure to the worker thread which
  843. // will free it. (Therefore, we don't want to free it.)
  844. //
  845. if (QueueUserWorkItemInThread (IncomingEventWorkItem,
  846. pEvent, EVENTMGR_CONMAN))
  847. {
  848. fFreeEvent = FALSE;
  849. }
  850. else
  851. {
  852. TraceTag (ttidEvents,
  853. "QueueUserWorkItem failed with error %d in RasEventNotify.",
  854. GetLastError ());
  855. }
  856. }
  857. }
  858. if (fFreeEvent)
  859. {
  860. FreeConmanEvent (pEvent);
  861. }
  862. }
  863. //+---------------------------------------------------------------------------
  864. //
  865. // Function: IncomingEventNotify
  866. //
  867. // Purpose: To be called when something changes on an Incoming Connection
  868. //
  869. // Arguments:
  870. // EventType [in] Type of the event
  871. // pConn [in] The INetConnection (only for CONNECTION_MODIFIED)
  872. // pszNewName [in] The name (for CONNECTION_RENAMED)
  873. // pguidConn [in] The GUID of the connection (for CONNECTION_RENAMED)
  874. //
  875. // Returns: nothing
  876. //
  877. // Author: sjkhan 17 Oct 2000
  878. //
  879. // Notes: The easy thing is done a full refresh is queued for the
  880. // connection manager to notify its clients of.
  881. //
  882. VOID
  883. IncomingEventNotify (
  884. CONMAN_EVENTTYPE EventType,
  885. INetConnection* pConn,
  886. PCWSTR pszNewName,
  887. const GUID * pguidConn) throw()
  888. {
  889. TraceFileFunc(ttidEvents);
  890. // Let's be sure we only do work if the service state is still running.
  891. // If we have a stop pending for example, we don't need to do anything.
  892. //
  893. if (SERVICE_RUNNING != _Module.DwServiceStatus ())
  894. {
  895. return;
  896. }
  897. // If the connection manager has no active connection points registered,
  898. // we don't need to do anything.
  899. //
  900. if (!CConnectionManager::FHasActiveConnectionPoints ())
  901. {
  902. return;
  903. }
  904. if ((REFRESH_ALL == EventType) && (g_cInRefreshAll >= MAX_IN_REFRESH_ALL))
  905. {
  906. return;
  907. }
  908. // Allocate a CONMAN_EVENT structure and initialize it from the
  909. // INCOMING information.
  910. //
  911. CONMAN_EVENT* pEvent = (CONMAN_EVENT*)MemAlloc (sizeof(CONMAN_EVENT));
  912. if (!pEvent)
  913. {
  914. TraceTag (ttidEvents,
  915. "Failed to allocate a new work item in IncomingEventNotify.");
  916. return;
  917. }
  918. ZeroMemory (pEvent, sizeof(CONMAN_EVENT));
  919. pEvent->ConnectionManager = CONMAN_INCOMING;
  920. pEvent->Type = EventType;
  921. BOOL fFreeEvent = TRUE;
  922. HRESULT hr = S_OK;
  923. if (pConn)
  924. {
  925. // pEvent->pProps is valid for modified events and added events, but we only support modified for incoming.
  926. // So, we don't want to be getting properties for any other event.
  927. //
  928. AssertSz (
  929. (CONNECTION_MODIFIED == EventType),
  930. "Why is pConn being passed for this event type?");
  931. hr = HrGetPropertiesExFromINetConnection(pConn, &pEvent->pPropsEx);
  932. }
  933. if (EventType == CONNECTION_RENAMED)
  934. {
  935. AssertSz(pszNewName, "Rename event requires szwNewName to be "
  936. "non-NULL");
  937. AssertSz(pguidConn, "Rename event requires pguidConn to be "
  938. "non-NULL");
  939. // Copy in the right info into the event struct
  940. //
  941. pEvent->guidId = *pguidConn;
  942. lstrcpynW(pEvent->szNewName, pszNewName, celems(pEvent->szNewName));
  943. }
  944. if (S_OK == hr)
  945. {
  946. TraceTag (ttidEvents,
  947. "IncomingEventNotify: Queuing ConmanEventWorkItem (Type=%s)...",
  948. DbgEvents(pEvent->Type));
  949. // Queue a worker to deliver the event to the clients of the
  950. // connection manager with registered connection points.
  951. // We pass ownership of the structure to the worker thread which
  952. // will free it. (Therefore, we don't want to free it.)
  953. //
  954. if (QueueUserWorkItemInThread (ConmanEventWorkItem,
  955. pEvent, EVENTMGR_CONMAN))
  956. {
  957. fFreeEvent = FALSE;
  958. }
  959. else
  960. {
  961. TraceTag (ttidEvents,
  962. "QueueUserWorkItem failed with error %d in IncomingEventNotify.",
  963. GetLastError ());
  964. }
  965. }
  966. if (fFreeEvent)
  967. {
  968. FreeConmanEvent (pEvent);
  969. }
  970. }
  971. //+---------------------------------------------------------------------------
  972. //
  973. // Function: DispatchEvents
  974. //
  975. // Purpose: Thread function for Dispatching events
  976. //
  977. // Arguments:
  978. // pUnused [in,out] Unused
  979. // fTimerFired [in] We are being signalled
  980. //
  981. // Returns: nothing
  982. //
  983. // Author: sjkhan 30 Nov 2000
  984. //
  985. // Notes: Is called when something is added to the queue and and an event
  986. // is set, then dispatches all events until the queue is empty
  987. // and then exits.
  988. //
  989. //
  990. VOID NTAPI DispatchEvents(IN OUT LPVOID pUnused, IN BOOLEAN fTimerFired) throw()
  991. {
  992. TraceFileFunc(ttidEvents);
  993. HRESULT hr = S_OK;
  994. TraceTag(ttidEvents, "Event Dispatching Thread Started.");
  995. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  996. if (SUCCEEDED(hr))
  997. {
  998. if (fTimerFired == FALSE /* We were signaled */)
  999. {
  1000. while (g_pEventQueue->AtomCheckSizeAndResetEvent(g_fDispatchEvents))
  1001. {
  1002. PCONMAN_EVENTTHREAD pfnEvent = NULL;
  1003. CONMAN_EVENT *pEvent = NULL;
  1004. EVENT_MANAGER EventMgr;
  1005. HRESULT hr;
  1006. TraceTag(ttidEvents, "Number of events in Queue: %d", g_pEventQueue->size());
  1007. hr = g_pEventQueue->DequeueEvent(pfnEvent, pEvent, EventMgr);
  1008. if (SUCCEEDED(hr) && pfnEvent)
  1009. {
  1010. pfnEvent(pEvent);
  1011. }
  1012. }
  1013. }
  1014. CoUninitialize();
  1015. }
  1016. else
  1017. {
  1018. TraceError("Error calling CoInitialize.", hr);
  1019. }
  1020. TraceTag(ttidEvents, "Event Dispatching Thread Stopping.");
  1021. }
  1022. //+---------------------------------------------------------------------------
  1023. //
  1024. // Function: HrEnsureEventHandlerInitialized
  1025. //
  1026. // Purpose: Thread function for Dispatching events
  1027. //
  1028. // Arguments:
  1029. // (none)
  1030. //
  1031. // Returns: HRESULT
  1032. //
  1033. // Author: sjkhan 30 Nov 2000
  1034. //
  1035. // Notes:
  1036. //
  1037. //
  1038. HRESULT HrEnsureEventHandlerInitialized()
  1039. {
  1040. TraceFileFunc(ttidEvents);
  1041. DWORD dwThreadId;
  1042. NTSTATUS Status;
  1043. HANDLE hEventExit;
  1044. HRESULT hr = S_FALSE; // Events are already initialized.
  1045. TraceTag(ttidEvents, "Entering HrEnsureEventHandlerInitialized");
  1046. if (!g_pEventQueue)
  1047. {
  1048. hEventExit = CreateEvent(NULL, FALSE, FALSE, NULL);
  1049. if (hEventExit)
  1050. {
  1051. try
  1052. {
  1053. g_pEventQueue = new CEventQueue(hEventExit); // This throws only HRESULT's
  1054. if (!g_pEventQueue)
  1055. {
  1056. throw E_OUTOFMEMORY;
  1057. }
  1058. // Check to see if we should handle incoming events.
  1059. DWORD dwErr = RasSrvAllowConnectionsConfig(&g_fHandleIncomingEvents);
  1060. TraceError ("RasSrvIsConnectionConnected", HRESULT_FROM_WIN32(dwErr));
  1061. g_fDispatchEvents = TRUE;
  1062. }
  1063. catch (HRESULT hrThrown)
  1064. {
  1065. hr = hrThrown;
  1066. }
  1067. CloseHandle(hEventExit);
  1068. }
  1069. else
  1070. {
  1071. hr = HrFromLastWin32Error();
  1072. }
  1073. }
  1074. TraceError("Error in HrEnsureEventHandlerInitialized", hr);
  1075. return hr;
  1076. }
  1077. //+---------------------------------------------------------------------------
  1078. //
  1079. // Function: UninitializeEventHandler
  1080. //
  1081. // Purpose:
  1082. //
  1083. // Arguments:
  1084. // (none)
  1085. //
  1086. // Returns: HRESULT
  1087. //
  1088. // Author: sjkhan 30 Nov 2000
  1089. //
  1090. // Notes:
  1091. //
  1092. //
  1093. HRESULT UninitializeEventHandler()
  1094. {
  1095. TraceFileFunc(ttidEvents);
  1096. HRESULT hr = S_OK;
  1097. DWORD dwStatus;
  1098. NTSTATUS Status;
  1099. TraceTag(ttidEvents, "Entering UninitializeEventHandler");
  1100. if (g_fDispatchEvents)
  1101. {
  1102. g_fDispatchEvents = FALSE;
  1103. if (g_pEventQueue && (0 != g_pEventQueue->size()))
  1104. {
  1105. dwStatus = g_pEventQueue->WaitForExit();
  1106. }
  1107. TraceTag(ttidEvents, "Deregistering Event Wait");
  1108. if (g_hEventWait)
  1109. {
  1110. Status = RtlDeregisterWaitEx(g_hEventWait, INVALID_HANDLE_VALUE);
  1111. g_hEventWait = NULL;
  1112. }
  1113. if (g_pEventQueue)
  1114. {
  1115. delete g_pEventQueue;
  1116. g_pEventQueue = NULL;
  1117. }
  1118. }
  1119. CGroupPolicyNetworkLocationAwareness* pGPNLA =
  1120. reinterpret_cast<CGroupPolicyNetworkLocationAwareness*>(InterlockedExchangePointer( (PVOID volatile *) &g_pGPNLA, NULL));
  1121. if (pGPNLA)
  1122. {
  1123. TraceTag(ttidEvents, "Calling Group Policy Uninitialize");
  1124. hr = pGPNLA->Uninitialize();
  1125. delete pGPNLA;
  1126. }
  1127. TraceError("UninitializeEventHandler", hr);
  1128. TraceTag(ttidEvents, "Exiting UninitializeEventHandler");
  1129. return S_OK;
  1130. }
  1131. //+---------------------------------------------------------------------------
  1132. //
  1133. // Function: QueueUserWorkItemInThread
  1134. //
  1135. // Purpose: Places events and their workitems into the event queue for
  1136. // scheduling.
  1137. // Arguments:
  1138. // LPTHREAD_START_ROUTINE [in] - worker function to call
  1139. // Context [in] - event data, allocate & pass a CONMAN_EVENT using operator new()
  1140. // EventMgr [in] - CONMAN or EAPOLMAN
  1141. //
  1142. //
  1143. // Returns: BOOL
  1144. //
  1145. // Author: sjkhan 30 Nov 2000
  1146. //
  1147. // Notes:
  1148. //
  1149. //
  1150. BOOL QueueUserWorkItemInThread(IN PCONMAN_EVENTTHREAD Function,
  1151. IN TAKEOWNERSHIP CONMAN_EVENT* Context,
  1152. IN EVENT_MANAGER EventMgr) throw()
  1153. {
  1154. TraceFileFunc(ttidEvents);
  1155. HRESULT hr = S_OK;
  1156. TraceTag(ttidEvents, "Entering QueueUserWorkItemInThread");
  1157. if (g_fDispatchEvents) // if we're shutting down then this will be FALSE and we won't be scheduling events.
  1158. {
  1159. hr = g_pEventQueue->EnqueueEvent(Function, Context, EventMgr);
  1160. // The queue should contain only one item at this point unless someone else has added something
  1161. // but either way, only one thread will be handling events (as the other call would have received S_OK
  1162. // as a return value), as we synchronize this in EnqueueEvent.
  1163. TraceTag(ttidEvents, "Number of Items in Queue: %d", g_pEventQueue->size());
  1164. }
  1165. TraceTag(ttidEvents, "Exiting QueueUserWorkItemInThread");
  1166. if (FAILED(hr))
  1167. {
  1168. TraceError("Error in QueueUserWorkItemInThread", hr);
  1169. }
  1170. return SUCCEEDED(hr);
  1171. }
  1172. //+---------------------------------------------------------------------------
  1173. //
  1174. // Function: IsValidEventType
  1175. //
  1176. // Purpose: Validate Event parameters.
  1177. //
  1178. // Arguments:
  1179. // EventMgr - type of event manager
  1180. // EventType - type of event
  1181. //
  1182. // Returns: HRESULT indicating success of failure
  1183. //
  1184. // Author: sjkhan 09 Dec 2000
  1185. //
  1186. // Notes:
  1187. //
  1188. //
  1189. //
  1190. //
  1191. BOOL IsValidEventType(IN EVENT_MANAGER EventMgr, IN int EventType) throw()
  1192. {
  1193. TraceFileFunc(ttidEvents);
  1194. BOOL fIsValid = FALSE;
  1195. Assert(EventMgr);
  1196. TraceTag(ttidEvents, "IsValidEventType received: %d", EventType);
  1197. if (EventMgr == EVENTMGR_CONMAN)
  1198. {
  1199. if (EventType == INVALID_TYPE)
  1200. {
  1201. fIsValid = FALSE;
  1202. }
  1203. else if (EventType <= DISABLE_EVENTS)
  1204. {
  1205. fIsValid = TRUE;
  1206. }
  1207. }
  1208. else
  1209. {
  1210. AssertSz(FALSE, "Invalid Event Manager");
  1211. }
  1212. return fIsValid;
  1213. }
  1214. //+---------------------------------------------------------------------------
  1215. //
  1216. // Function: HrEnsureRegisteredWithNla
  1217. //
  1218. // Purpose: Initialize our Nla Event class, if not already done.
  1219. //
  1220. // Arguments:
  1221. // (none)
  1222. //
  1223. // Returns: HRESULT indicating success of failure
  1224. //
  1225. // Author: sjkhan 21 Apr 2001
  1226. //
  1227. // Notes:
  1228. //
  1229. //
  1230. //
  1231. HRESULT HrEnsureRegisteredWithNla()
  1232. {
  1233. TraceFileFunc(ttidEvents);
  1234. HRESULT hr = S_FALSE; // We're already registered, no need to do so again.
  1235. if (!g_pGPNLA)
  1236. {
  1237. try
  1238. {
  1239. g_pGPNLA = new CGroupPolicyNetworkLocationAwareness();
  1240. if (g_pGPNLA)
  1241. {
  1242. hr = g_pGPNLA->Initialize();
  1243. if (FAILED(hr))
  1244. {
  1245. TraceError("Error in HrEnsureRegisteredWithNla", hr);
  1246. delete g_pGPNLA;
  1247. g_pGPNLA = NULL;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. hr = E_OUTOFMEMORY;
  1253. }
  1254. }
  1255. catch (HRESULT hrThrown)
  1256. {
  1257. hr = hrThrown;
  1258. }
  1259. // CGroupPolicyNetworkLocationAwareness constructor can throw
  1260. // a bad_alloc because it contains a STL list member.
  1261. catch (bad_alloc)
  1262. {
  1263. hr = E_OUTOFMEMORY;
  1264. }
  1265. }
  1266. TraceTag(ttidEvents, "Exiting HrEnsureRegisteredWithNla");
  1267. return hr;
  1268. }