338 lines
9.1 KiB
C++
338 lines
9.1 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: A R C . C P P
|
||
|
//
|
||
|
// Contents: Notification support for active ras connections.
|
||
|
//
|
||
|
// Notes: This module maintains a global array of active RAS connections.
|
||
|
// This array is initialized with a call to
|
||
|
// HrArcEnsureCachedAndListening. A thread waits for
|
||
|
// notifications that a RAS connection has either been connected
|
||
|
// or disconnected. When this happens, the thread calls
|
||
|
// ArcWaitCallback which updates the
|
||
|
// global array. The thread gets its handle to wait on from
|
||
|
// HrArcEnsureCachedAndListening. The thread is not implemented
|
||
|
// here but rather a sytem-provide thread pool is used.
|
||
|
//
|
||
|
// Author: shaunco 7 Feb 1998
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
#include "arc.h"
|
||
|
#include "conman.h"
|
||
|
#include "ncmisc.h"
|
||
|
#include "ncras.h"
|
||
|
#include "nmbase.h"
|
||
|
#include <raserror.h>
|
||
|
|
||
|
ASSERTDATA;
|
||
|
|
||
|
|
||
|
// This is the global data representing active ras connections.
|
||
|
//
|
||
|
struct ACTIVE_RAS_CONNECTIONS
|
||
|
{
|
||
|
// This is set after calling ArcInitialize.
|
||
|
//
|
||
|
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.
|
||
|
//
|
||
|
RASCONN* 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 HrArcEnsureCachedAndListening.
|
||
|
//
|
||
|
BOOL fCachedAndListening;
|
||
|
};
|
||
|
|
||
|
ACTIVE_RAS_CONNECTIONS g_Arc = { 0 };
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ArcInitialize
|
||
|
//
|
||
|
// Purpose: Initialize this module for use.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
// Author: shaunco 7 Feb 1998
|
||
|
//
|
||
|
// Notes: This can only be called once. It must be called before
|
||
|
// any other Arc* API can be called.
|
||
|
//
|
||
|
VOID
|
||
|
ArcInitialize ()
|
||
|
{
|
||
|
Assert (!g_Arc.fInitialized);
|
||
|
|
||
|
InitializeCriticalSection (&g_Arc.critsec);
|
||
|
g_Arc.fInitialized = TRUE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ArcUninitialize
|
||
|
//
|
||
|
// Purpose: Uninitialize this module.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
// Author: shaunco 7 Feb 1998
|
||
|
//
|
||
|
// Notes: This can only be called once. It must be called after the
|
||
|
// last call to any other Arc* API.
|
||
|
//
|
||
|
VOID
|
||
|
ArcUninitialize ()
|
||
|
{
|
||
|
Assert (g_Arc.fInitialized);
|
||
|
|
||
|
if (g_Arc.fCachedAndListening)
|
||
|
{
|
||
|
CExceptionSafeLock EsLock (&g_Arc.critsec);
|
||
|
|
||
|
if (g_Arc.hWait)
|
||
|
{
|
||
|
TraceTag (ttidWanCon, "ArcUninitialize: calling RtlDeregisterWait");
|
||
|
|
||
|
RtlDeregisterWait (g_Arc.hWait);
|
||
|
g_Arc.hWait = NULL;
|
||
|
}
|
||
|
|
||
|
TraceTag (ttidWanCon, "ArcUninitialize: closing event handle");
|
||
|
CloseHandle (g_Arc.hEvent);
|
||
|
g_Arc.hEvent = NULL;
|
||
|
|
||
|
MemFree (g_Arc.aRasConn);
|
||
|
g_Arc.aRasConn = NULL;
|
||
|
g_Arc.cRasConn = 0;
|
||
|
|
||
|
g_Arc.fCachedAndListening = FALSE;
|
||
|
}
|
||
|
|
||
|
// We can't delete the critical section unless we can guarantee
|
||
|
// that no other API (like HrArcFindRasConnFromGuidId)
|
||
|
// will be called. (This is assumed.)
|
||
|
//
|
||
|
DeleteCriticalSection (&g_Arc.critsec);
|
||
|
g_Arc.fInitialized = FALSE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ArcWaitCallback
|
||
|
//
|
||
|
// Purpose: Called by the RTL thread pool for this process when
|
||
|
// g_Arc.hEvent is signaled. This event will be signaled by
|
||
|
// the Rasman service when the state of an outgoing
|
||
|
// 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 7 Feb 1998
|
||
|
//
|
||
|
// Notes: Be quick about this. We're being called on a thread provided
|
||
|
// by the system.
|
||
|
//
|
||
|
VOID
|
||
|
NTAPI
|
||
|
ArcWaitCallback (
|
||
|
PVOID pvContext,
|
||
|
BOOLEAN fTimeout)
|
||
|
{
|
||
|
Assert (g_Arc.fInitialized);
|
||
|
Assert (g_Arc.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, "ArcWaitCallback called while service is not "
|
||
|
"in SERVICE_RUNNING state. Ignoring.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// Lock scope
|
||
|
{
|
||
|
// Prevent other threads from reading the data we are about to update.
|
||
|
//
|
||
|
CExceptionSafeLock EsLock (&g_Arc.critsec);
|
||
|
|
||
|
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, "ArcWaitCallback");
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
HrArcEnsureCachedAndListening ()
|
||
|
{
|
||
|
Assert (g_Arc.fInitialized);
|
||
|
|
||
|
if (g_Arc.fCachedAndListening)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
g_Arc.fCachedAndListening = TRUE;
|
||
|
TraceTag (ttidWanCon, "Initializing active ras "
|
||
|
"connections cache...");
|
||
|
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
// Prevent other threads from reading the data we are about to update.
|
||
|
//
|
||
|
CExceptionSafeLock EsLock (&g_Arc.critsec);
|
||
|
|
||
|
// Create an auto-reset event and register it with
|
||
|
// RasConnectionNotification.
|
||
|
//
|
||
|
g_Arc.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||
|
if (g_Arc.hEvent)
|
||
|
{
|
||
|
// We want to register for state changes to all connection objects
|
||
|
// so we pass INVALID_HANDLE_VALUE for the first parameter.
|
||
|
//
|
||
|
DWORD dwErr = RasConnectionNotification (
|
||
|
reinterpret_cast<HRASCONN>(INVALID_HANDLE_VALUE),
|
||
|
g_Arc.hEvent,
|
||
|
RASCN_Connection | RASCN_Disconnection |
|
||
|
RASCN_BandwidthAdded | RASCN_BandwidthRemoved);
|
||
|
|
||
|
hr = HRESULT_FROM_WIN32 (dwErr);
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "RasConnectionNotification", hr);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Initialize the array of active RAS connections before
|
||
|
// registering for a wait callack on the event.
|
||
|
//
|
||
|
MemFree (g_Arc.aRasConn);
|
||
|
hr = HrRasEnumAllActiveConnections (&g_Arc.aRasConn,
|
||
|
&g_Arc.cRasConn);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
status = RtlRegisterWait (&g_Arc.hWait, g_Arc.hEvent,
|
||
|
ArcWaitCallback, 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 "
|
||
|
"ras connection state changes...");
|
||
|
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
MemFree (g_Arc.aRasConn);
|
||
|
g_Arc.aRasConn = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
CloseHandle (g_Arc.hEvent);
|
||
|
g_Arc.hEvent = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HrFromLastWin32Error ();
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "CreateEvent", hr);
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "HrArcEnsureCachedAndListening");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
HrArcFindRasConnFromGuidId (
|
||
|
const GUID* pguidId,
|
||
|
HRASCONN* phRasConn)
|
||
|
{
|
||
|
Assert (g_Arc.fInitialized);
|
||
|
Assert (pguidId);
|
||
|
Assert (phRasConn);
|
||
|
|
||
|
// Initialize the output parameter.
|
||
|
//
|
||
|
*phRasConn = NULL;
|
||
|
|
||
|
HRESULT hr = S_FALSE;
|
||
|
|
||
|
// Prevent the update thread from updating the data
|
||
|
// until we are done reading it.
|
||
|
//
|
||
|
CExceptionSafeLock EsLock (&g_Arc.critsec);
|
||
|
|
||
|
for (DWORD dwIndex = 0; dwIndex < g_Arc.cRasConn; dwIndex++)
|
||
|
{
|
||
|
if (*pguidId == g_Arc.aRasConn[dwIndex].guidEntry)
|
||
|
{
|
||
|
*phRasConn = g_Arc.aRasConn[dwIndex].hrasconn;
|
||
|
hr = S_OK;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, (S_FALSE == hr),
|
||
|
"HrArcFindRasConnFromGuidId");
|
||
|
return hr;
|
||
|
}
|