488 lines
14 KiB
C++
488 lines
14 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: E N U M I . C P P
|
||
|
//
|
||
|
// Contents: Enumerator for Inbound connection objects.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: shaunco 12 Nov 1997
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
#include "enumi.h"
|
||
|
#include "inbound.h"
|
||
|
#include "ncras.h"
|
||
|
#include "ncsvc.h"
|
||
|
|
||
|
|
||
|
LONG g_CountIncomingConnectionEnumerators;
|
||
|
|
||
|
|
||
|
extern const WCHAR c_szSvcRemoteAccess[];
|
||
|
extern const GUID GUID_InboundConfigConnectionId;
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CInboundConnectionManagerEnumConnection::CreateInstance
|
||
|
//
|
||
|
// Purpose: Creates the Inbound class manager's implementation of
|
||
|
// a connection enumerator.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// Flags [in]
|
||
|
// riid [in]
|
||
|
// ppv [out]
|
||
|
//
|
||
|
// Returns: S_OK or an error code.
|
||
|
//
|
||
|
// Author: shaunco 12 Nov 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
CInboundConnectionManagerEnumConnection::CreateInstance (
|
||
|
NETCONMGR_ENUM_FLAGS Flags,
|
||
|
REFIID riid,
|
||
|
VOID** ppv)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
|
||
|
CInboundConnectionManagerEnumConnection* pObj;
|
||
|
pObj = new CComObject <CInboundConnectionManagerEnumConnection>;
|
||
|
if (pObj)
|
||
|
{
|
||
|
// Initialize our members.
|
||
|
//
|
||
|
pObj->m_EnumFlags = Flags;
|
||
|
|
||
|
pObj->m_fReturnedConfig = FALSE;
|
||
|
|
||
|
// Do the standard CComCreator::CreateInstance stuff.
|
||
|
//
|
||
|
pObj->SetVoid (NULL);
|
||
|
pObj->InternalFinalConstructAddRef ();
|
||
|
hr = pObj->FinalConstruct ();
|
||
|
pObj->InternalFinalConstructRelease ();
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pObj->QueryInterface (riid, ppv);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
delete pObj;
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CInboundConnectionManagerEnumConnection::CInboundConnectionManagerEnumConnection ()
|
||
|
{
|
||
|
InterlockedIncrement (&g_CountIncomingConnectionEnumerators);
|
||
|
|
||
|
m_EnumFlags = NCME_DEFAULT;
|
||
|
m_aRasSrvConn = NULL;
|
||
|
m_cRasSrvConn = 0;
|
||
|
m_iNextRasSrvConn = 0;
|
||
|
m_fFirstTime = TRUE;
|
||
|
m_fDone = FALSE;
|
||
|
}
|
||
|
|
||
|
CInboundConnectionManagerEnumConnection::~CInboundConnectionManagerEnumConnection ()
|
||
|
{
|
||
|
MemFree (m_aRasSrvConn);
|
||
|
|
||
|
InterlockedDecrement (&g_CountIncomingConnectionEnumerators);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCreateConfigOrCurrentEnumeratedConnection
|
||
|
//
|
||
|
// Purpose: Parameterize the call to CInboundConnection::CreateInstance
|
||
|
// based on whether we are returning the configuration
|
||
|
// connection or the currently enumerated one.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// fIsConfigConnection [in]
|
||
|
// ppCon [out]
|
||
|
//
|
||
|
// Returns: S_OK or an error code.
|
||
|
//
|
||
|
// Author: shaunco 16 Nov 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
CInboundConnectionManagerEnumConnection::
|
||
|
HrCreateConfigOrCurrentEnumeratedConnection (
|
||
|
BOOL fIsConfigConnection,
|
||
|
INetConnection** ppCon)
|
||
|
{
|
||
|
// Parameterize the call to
|
||
|
// CInboundConnection::CreateInstance based on whether
|
||
|
// we are returning the configuration connection or the currently
|
||
|
// enumerated one.
|
||
|
//
|
||
|
HRASSRVCONN hRasSrvConn;
|
||
|
PCWSTR pszName;
|
||
|
PCWSTR pszDeviceName;
|
||
|
DWORD dwType;
|
||
|
const GUID* pguidId;
|
||
|
|
||
|
if (fIsConfigConnection)
|
||
|
{
|
||
|
hRasSrvConn = 0;
|
||
|
pszName = NULL;
|
||
|
pszDeviceName = NULL;
|
||
|
dwType = 0;
|
||
|
pguidId = &GUID_InboundConfigConnectionId;
|
||
|
m_fReturnedConfig = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hRasSrvConn = m_aRasSrvConn[m_iNextRasSrvConn].hRasSrvConn;
|
||
|
pszName = m_aRasSrvConn[m_iNextRasSrvConn].szEntryName;
|
||
|
pszDeviceName = m_aRasSrvConn[m_iNextRasSrvConn].szDeviceName;
|
||
|
dwType = m_aRasSrvConn[m_iNextRasSrvConn].dwType;
|
||
|
pguidId = &m_aRasSrvConn[m_iNextRasSrvConn].Guid;
|
||
|
|
||
|
m_iNextRasSrvConn++;
|
||
|
}
|
||
|
|
||
|
HRESULT hr = CInboundConnection::CreateInstance (
|
||
|
fIsConfigConnection,
|
||
|
hRasSrvConn,
|
||
|
pszName,
|
||
|
pszDeviceName,
|
||
|
dwType,
|
||
|
pguidId,
|
||
|
IID_INetConnection,
|
||
|
reinterpret_cast<VOID**>(ppCon));
|
||
|
|
||
|
TraceError ("CInboundConnectionManagerEnumConnection::"
|
||
|
"HrCreateConfigOrCurrentEnumeratedConnection", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CInboundConnectionManagerEnumConnection::HrNextOrSkip
|
||
|
//
|
||
|
// Purpose: Common implementation of Next and Skip. rgelt and
|
||
|
// pceltFetched are optional. If provided, the output
|
||
|
// objects are returned (for Next). If not provided, the output
|
||
|
// objects are not returned (for Skip).
|
||
|
//
|
||
|
// Arguments:
|
||
|
// celt [in] Count of elements to fetch or skip.
|
||
|
// rgelt [out]
|
||
|
// pceltFetched [out]
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: shaunco 12 Nov 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
CInboundConnectionManagerEnumConnection::HrNextOrSkip (
|
||
|
ULONG celt,
|
||
|
INetConnection** rgelt,
|
||
|
ULONG* pceltFetched)
|
||
|
{
|
||
|
// Important to initialize rgelt so that in case we fail, we can
|
||
|
// release only what we put in rgelt.
|
||
|
//
|
||
|
if (rgelt)
|
||
|
{
|
||
|
ZeroMemory (rgelt, sizeof (*rgelt) * celt);
|
||
|
}
|
||
|
|
||
|
CExceptionSafeComObjectLock EsLock (this);
|
||
|
|
||
|
// Enumerate the requested number of elements or stop short
|
||
|
// if we don't have that many left to enumerate. We don't enumerate
|
||
|
// anything specific to the current user. All elements are for all
|
||
|
// users.
|
||
|
//
|
||
|
HRESULT hr = S_OK;
|
||
|
ULONG celtFetched = 0;
|
||
|
if ((celtFetched < celt) && !m_fDone)
|
||
|
{
|
||
|
// This gets set to TRUE if we are to return the configuration
|
||
|
// connection. This only happens when RAS is running and no
|
||
|
// active connections exist.
|
||
|
//
|
||
|
BOOL fReturnConfigCon = FALSE;
|
||
|
|
||
|
// If this is our first time through, we need to check if the server
|
||
|
// is running and possibly fill up m_aRasSrvConn. This is our
|
||
|
// array of RASSRVCONN handles enumerted from RAS. We need
|
||
|
// to keep this array across calls because RAS doesn't allow us to
|
||
|
// pickup from a previous enumeration. So, we enumerate everything
|
||
|
// in one shot from RAS and hand it out to the caller however they
|
||
|
// they want it.
|
||
|
//
|
||
|
if (m_fFirstTime)
|
||
|
{
|
||
|
m_fFirstTime = FALSE;
|
||
|
|
||
|
// Assert is so that we don't set m_fDone back to FALSE
|
||
|
// in the case where the service is suddenly running again.
|
||
|
// The enumerator is static. Once done, always done.
|
||
|
//
|
||
|
AssertSz (!m_fDone, "How'd we get here if we're done?");
|
||
|
|
||
|
// Use HrSvcQueryStatus instead of RasSrvIsServiceRunning since
|
||
|
// calling the latter could page in all of the RAS DLLs. If
|
||
|
// the service isn't running, we have nothing to enumerate anyway
|
||
|
// so if we were to page in the RAS DLLs only to find that we
|
||
|
// have no further work to do.
|
||
|
//
|
||
|
DWORD dwState;
|
||
|
HRESULT hrT = HrSvcQueryStatus (c_szSvcRemoteAccess, &dwState);
|
||
|
m_fDone = FAILED(hrT) || (SERVICE_RUNNING != dwState);
|
||
|
|
||
|
if (!m_fDone)
|
||
|
{
|
||
|
hr = HrRasEnumAllActiveServerConnections (&m_aRasSrvConn,
|
||
|
&m_cRasSrvConn);
|
||
|
|
||
|
// If no active connections returned, we need to return
|
||
|
// the configuration connection.
|
||
|
//
|
||
|
if (SUCCEEDED(hr) && (!m_aRasSrvConn || !m_cRasSrvConn || !m_fReturnedConfig))
|
||
|
{
|
||
|
// See if RAS allows us to configure incoming
|
||
|
// connections.
|
||
|
//
|
||
|
BOOL fAllowConfig;
|
||
|
DWORD dwErr = RasSrvAllowConnectionsConfig (&fAllowConfig);
|
||
|
TraceError ("RasSrvAllowConnectionsConfig",
|
||
|
HRESULT_FROM_WIN32 (dwErr));
|
||
|
|
||
|
fReturnConfigCon = ((ERROR_SUCCESS == dwErr) &&
|
||
|
fAllowConfig);
|
||
|
|
||
|
// We're done if we're not returning the config connection.
|
||
|
//
|
||
|
m_fDone = !fReturnConfigCon;
|
||
|
}
|
||
|
else if (FAILED(hr))
|
||
|
{
|
||
|
// Return an empty enumeration on any failures.
|
||
|
//
|
||
|
Assert (!m_aRasSrvConn);
|
||
|
Assert (!m_cRasSrvConn);
|
||
|
|
||
|
m_fDone = TRUE;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we're not done, and we need to return something, do it.
|
||
|
//
|
||
|
if (SUCCEEDED(hr) && !m_fDone && (m_cRasSrvConn || fReturnConfigCon))
|
||
|
{
|
||
|
// If we're not returning the configuration connection, it means
|
||
|
// we must be returning an active connection.
|
||
|
//
|
||
|
Assert (FImplies (!fReturnConfigCon, m_aRasSrvConn));
|
||
|
Assert (FImplies (!fReturnConfigCon,
|
||
|
m_iNextRasSrvConn < m_cRasSrvConn));
|
||
|
|
||
|
// For each entry returned, create the inbound connection object.
|
||
|
//
|
||
|
while (SUCCEEDED(hr) && (celtFetched < celt) &&
|
||
|
(fReturnConfigCon || (m_iNextRasSrvConn < m_cRasSrvConn)))
|
||
|
{
|
||
|
// Its important that this check for rgelt come inside the
|
||
|
// loop because we still need to loop to update our state
|
||
|
// for the Skip case.
|
||
|
//
|
||
|
if (rgelt)
|
||
|
{
|
||
|
hr = HrCreateConfigOrCurrentEnumeratedConnection (
|
||
|
fReturnConfigCon,
|
||
|
rgelt + celtFetched);
|
||
|
}
|
||
|
|
||
|
if (fReturnConfigCon)
|
||
|
{
|
||
|
// Only return one of these, so set it back to false.
|
||
|
// This let's the loop complete above.
|
||
|
//
|
||
|
fReturnConfigCon = FALSE;
|
||
|
// m_fDone = TRUE;
|
||
|
}
|
||
|
|
||
|
celtFetched++;
|
||
|
}
|
||
|
|
||
|
if (m_iNextRasSrvConn >= m_cRasSrvConn)
|
||
|
{
|
||
|
Assert (S_OK == hr);
|
||
|
m_fDone = TRUE;
|
||
|
MemFree (m_aRasSrvConn);
|
||
|
m_aRasSrvConn = NULL;
|
||
|
m_cRasSrvConn = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
TraceTag (ttidWanCon, "Enumerated %d incoming connections",
|
||
|
celtFetched);
|
||
|
|
||
|
if (pceltFetched)
|
||
|
{
|
||
|
*pceltFetched = celtFetched;
|
||
|
}
|
||
|
hr = (celtFetched == celt) ? S_OK : S_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// For any failures, we need to release what we were about to return.
|
||
|
// Set any output parameters to NULL.
|
||
|
//
|
||
|
if (rgelt)
|
||
|
{
|
||
|
for (ULONG ulIndex = 0; ulIndex < celt; ulIndex++)
|
||
|
{
|
||
|
ReleaseObj (rgelt[ulIndex]);
|
||
|
rgelt[ulIndex] = NULL;
|
||
|
}
|
||
|
}
|
||
|
if (pceltFetched)
|
||
|
{
|
||
|
*pceltFetched = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceError ("CInboundConnectionManagerEnumConnection::HrNextOrSkip",
|
||
|
(S_FALSE == hr) ? S_OK : hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
// IEnumNetConnection
|
||
|
//
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CInboundConnectionManagerEnumConnection::Next (
|
||
|
ULONG celt,
|
||
|
INetConnection** rgelt,
|
||
|
ULONG* pceltFetched)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
// Validate parameters.
|
||
|
//
|
||
|
if (!rgelt || (!pceltFetched && (1 != celt)))
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HrNextOrSkip (celt, rgelt, pceltFetched);
|
||
|
}
|
||
|
TraceError ("CInboundConnectionManagerEnumConnection::Next",
|
||
|
(S_FALSE == hr) ? S_OK : hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CInboundConnectionManagerEnumConnection::Skip (
|
||
|
ULONG celt)
|
||
|
{
|
||
|
HRESULT hr = HrNextOrSkip (celt, NULL, NULL);
|
||
|
|
||
|
TraceError ("CInboundConnectionManagerEnumConnection::Skip",
|
||
|
(S_FALSE == hr) ? S_OK : hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CInboundConnectionManagerEnumConnection::Reset ()
|
||
|
{
|
||
|
CExceptionSafeComObjectLock EsLock (this);
|
||
|
|
||
|
MemFree (m_aRasSrvConn);
|
||
|
m_aRasSrvConn = NULL;
|
||
|
|
||
|
m_cRasSrvConn = 0;
|
||
|
m_iNextRasSrvConn = 0;
|
||
|
m_fFirstTime = TRUE;
|
||
|
m_fDone = FALSE;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CInboundConnectionManagerEnumConnection::Clone (
|
||
|
IEnumNetConnection** ppenum)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
|
||
|
// Validate parameters.
|
||
|
//
|
||
|
if (!ppenum)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Initialize output parameter.
|
||
|
//
|
||
|
*ppenum = NULL;
|
||
|
|
||
|
CInboundConnectionManagerEnumConnection* pObj;
|
||
|
pObj = new CComObject <CInboundConnectionManagerEnumConnection>;
|
||
|
if (pObj)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
|
||
|
CExceptionSafeComObjectLock EsLock (this);
|
||
|
|
||
|
// Copy our internal state.
|
||
|
//
|
||
|
pObj->m_EnumFlags = m_EnumFlags;
|
||
|
|
||
|
ULONG cbBuf = m_cRasSrvConn * sizeof (RASSRVCONN);
|
||
|
|
||
|
hr = HrMalloc (cbBuf, (PVOID*)&pObj->m_aRasSrvConn);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CopyMemory (pObj->m_aRasSrvConn, m_aRasSrvConn, cbBuf);
|
||
|
pObj->m_cRasSrvConn = m_cRasSrvConn;
|
||
|
|
||
|
pObj->m_iNextRasSrvConn = m_iNextRasSrvConn;
|
||
|
pObj->m_fFirstTime = m_fFirstTime;
|
||
|
pObj->m_fDone = m_fDone;
|
||
|
|
||
|
// Return the object with a ref count of 1 on this
|
||
|
// interface.
|
||
|
pObj->m_dwRef = 1;
|
||
|
*ppenum = pObj;
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
delete pObj;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
TraceError ("CInboundConnectionManagerEnumConnection::Clone", hr);
|
||
|
return hr;
|
||
|
}
|