//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: A I C . C P P // // Contents: Notification support for active inbound ras connections. // // Notes: // // Author: shaunco 24 Feb 1998 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "aic.h" #include "conman.h" #include "mprapi.h" #include "ncmisc.h" #include "nmbase.h" #include ASSERTDATA; // This is the global data representing active inbound ras connections. // struct ACTIVE_INBOUND_RAS_CONNECTIONS { // This is set after calling AicInitialize. // BOOL fInitialized; // This critical section protects reading and writing to members of // this structure. // CRITICAL_SECTION critsec; // This is the array and count of active ras connections. // // Note: (shaunco) 28 Apr 1998: RASSRVCONN is too big to keep an // array off. We'll have to roll our own structure and keep what's // important. // RASSRVCONN* aRasConn; // DWORD cRasConn; // This is the event handle that is signled when a connection is // connected or disconnected. // HANDLE hEvent; // This is the wait handle returned from RtlRegisterWait. // HANDLE hWait; // This is set after the first call to HrAicEnsureCachedAndListening. // BOOL fCachedAndListening; }; ACTIVE_INBOUND_RAS_CONNECTIONS g_Aic = { 0 }; //+--------------------------------------------------------------------------- // // Function: AicInitialize // // Purpose: Initialize this module for use. // // Arguments: // (none) // // Returns: nothing // // Author: shaunco 24 Feb 1998 // // Notes: This can only be called once. It must be called before // any other Aic* API can be called. // VOID AicInitialize () { Assert (!g_Aic.fInitialized); InitializeCriticalSection (&g_Aic.critsec); g_Aic.fInitialized = TRUE; } //+--------------------------------------------------------------------------- // // Function: AicUninitialize // // Purpose: Uninitialize this module. // // Arguments: // (none) // // Returns: nothing // // Author: shaunco 24 Feb 1998 // // Notes: This can only be called once. It must be called after the // last call to any other Aic* API. // VOID AicUninitialize () { Assert (g_Aic.fInitialized); if (g_Aic.fCachedAndListening) { CExceptionSafeLock EsLock (&g_Aic.critsec); if (g_Aic.hWait) { TraceTag (ttidWanCon, "AicUninitialize: calling RtlDeregisterWait"); RtlDeregisterWait (g_Aic.hWait); g_Aic.hWait = NULL; } TraceTag (ttidWanCon, "AicUninitialize: closing event handle"); CloseHandle (g_Aic.hEvent); g_Aic.hEvent = NULL; // MemFree (g_Aic.aRasConn); // g_Aic.aRasConn = NULL; // g_Aic.cRasConn = 0; g_Aic.fCachedAndListening = FALSE; } // We can't delete the critical section unless we can guarantee // that no other API (like HrAicFindRasConnFromGuidId) // will be called. (This is assumed.) // DeleteCriticalSection (&g_Aic.critsec); g_Aic.fInitialized = FALSE; } //+--------------------------------------------------------------------------- // // Function: AicWaitCallback // // Purpose: Called by the RTL thread pool for this process when // g_Aic.hEvent is signaled. This event will be signaled by // the RemoteAccess service when the state of an incoming // connection changes. // // Arguments: // pvContext [in] Our user data. (Not used here.) // fTimeout [in] TRUE if we were called because of a timeout. // // Returns: nothing // // Author: shaunco 24 Feb 1998 // // Notes: Be quick about this. We're being called on a thread provided // by the system. // VOID NTAPI AicWaitCallback ( PVOID pvContext, BOOLEAN fTimeout) { Assert (g_Aic.fInitialized); Assert (g_Aic.fCachedAndListening); // Let's be sure we only do work if the service state is still running. // If we have a stop pending for example, we don't need to do anything. // if (SERVICE_RUNNING != _Module.DwServiceStatus ()) { TraceTag (ttidWanCon, "AicWaitCallback called while service is not " "in SERVICE_RUNNING state. Ignoring."); return; } TraceTag (ttidWanCon, "AicWaitCallback called"); HRESULT hr = S_OK; // Lock scope { // Prevent other threads from reading the data we are about to update. // /* DWORD cRasConnOld = g_Arc.cRasConn; MemFree (g_Arc.aRasConn); hr = HrRasEnumAllActiveConnections (&g_Arc.aRasConn, &g_Arc.cRasConn); TraceTag (ttidWanCon, "ArcWaitCallback called: connection count: %u -> %u", cRasConnOld, g_Arc.cRasConn); */ } // Tell the connection manager to advise it's clients that a change // occured and re-enumeration is neccessary. // CConnectionManager::NotifyClientsOfChange (); TraceHr (ttidError, FAL, hr, FALSE, "AicWaitCallback"); } HRESULT HrAicEnsureCachedAndListening () { Assert (g_Aic.fInitialized); if (g_Aic.fCachedAndListening) { return S_OK; } g_Aic.fCachedAndListening = TRUE; TraceTag (ttidWanCon, "Initializing active incoming ras " "connections cache..."); HRESULT hr = E_FAIL; CExceptionSafeLock EsLock (&g_Aic.critsec); // Create a auto-reset event and register it with // MprAdminConnectionNotification. // g_Aic.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); if (g_Aic.hEvent) { HANDLE hMprAdmin; DWORD dwErr = MprAdminServerConnect (NULL, &hMprAdmin); hr = HRESULT_FROM_WIN32 (dwErr); TraceHr (ttidError, FAL, hr, FALSE, "MprAdminServerConnect", hr); if (SUCCEEDED(hr)) { dwErr = MprAdminRegisterConnectionNotification ( hMprAdmin, g_Aic.hEvent); hr = HRESULT_FROM_WIN32 (dwErr); TraceHr (ttidError, FAL, hr, FALSE, "MprAdminRegisterConnectionNotification", hr); if (SUCCEEDED(hr)) { NTSTATUS status; status = RtlRegisterWait (&g_Aic.hWait, g_Aic.hEvent, AicWaitCallback, NULL, INFINITE, WT_EXECUTEDEFAULT); if (!NT_SUCCESS(status)) { hr = HRESULT_FROM_NT (status); TraceHr (ttidError, FAL, hr, FALSE, "RtlRegisterWait", hr); } else { TraceTag (ttidWanCon, "Cached and listening for " "incoming ras connection state changes..."); hr = S_OK; } if (FAILED(hr)) { MprAdminDeregisterConnectionNotification (hMprAdmin, g_Aic.hEvent); } } MprAdminServerDisconnect (hMprAdmin); } if (FAILED(hr)) { CloseHandle (g_Aic.hEvent); g_Aic.hEvent = NULL; } } else { hr = HrFromLastWin32Error (); TraceHr (ttidError, FAL, hr, FALSE, "CreateEvent", hr); } TraceHr (ttidError, FAL, hr, FALSE, "HrAicEnsureCachedAndListening"); return hr; }