Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

337 lines
9.1 KiB

//+---------------------------------------------------------------------------
//
// 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;
}