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