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.

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