|
|
//******************************************************************************
//
// PROVREG.CPP
//
// Copyright (C) 1996-1999 Microsoft Corporation
//
//******************************************************************************
#include "precomp.h"
#include <stdio.h>
#include <parmdefs.h>
#include <ql.h>
#include "ess.h"
#include <wbemutil.h>
#include <cominit.h>
#include <objpath.h>
#include <provinit.h>
#include <winmgmtr.h>
#include <comutl.h>
#include "NCEvents.h"
_IWmiObject* g_pCopy;
#define WBEM_MAX_FILTER_ID 0x80000000
inline BOOL IsRpcError( HRESULT hr ) { //
// we'll consider any error but a wbem error to be an rpc error.
//
return HRESULT_FACILITY(hr) != FACILITY_ITF; }
CWbemInterval CEventProviderWatchInstruction::mstatic_Interval;
CEventProviderWatchInstruction::CEventProviderWatchInstruction( CEventProviderCache* pCache) : CBasicUnloadInstruction(mstatic_Interval), m_pCache(pCache) { }
void CEventProviderWatchInstruction::staticInitialize(IWbemServices* pRoot) { mstatic_Interval = CBasicUnloadInstruction::staticRead(pRoot, GetCurrentEssContext(), L"__EventProviderCacheControl=@"); }
HRESULT CEventProviderWatchInstruction::Fire(long, CWbemTime) { CInCritSec ics(&m_cs);
if(!m_bTerminate) { SetCurrentEssThreadObject(NULL); if ( GetCurrentEssThreadObject() != NULL ) { m_pCache->UnloadUnusedProviders(m_Interval); delete GetCurrentEssThreadObject(); ClearCurrentEssThreadObject(); } }
return WBEM_S_FALSE; }
//******************************************************************************
//******************************************************************************
//
// PROVIDER SINK (SERVER)
//
//******************************************************************************
//******************************************************************************
CProviderSinkServer::CEventDestination::CEventDestination( WBEM_REMOTE_TARGET_ID_TYPE id, CAbstractEventSink* pSink) : m_id(id), m_pSink(pSink) { if(m_pSink) m_pSink->AddRef(); }
CProviderSinkServer::CEventDestination::CEventDestination( const CEventDestination& Other) : m_id(Other.m_id), m_pSink(Other.m_pSink) { if(m_pSink) m_pSink->AddRef(); }
CProviderSinkServer::CEventDestination::~CEventDestination() { if(m_pSink) m_pSink->Release(); }
CProviderSinkServer::CProviderSinkServer() : m_lRef(0), m_pNamespace(NULL), m_pMetaData(NULL), m_Stub(this), m_idNext(0), m_pPseudoProxy(NULL), m_pPseudoSink(NULL), m_pReqSink(NULL), m_lLocks(0) { }
HRESULT CProviderSinkServer::Initialize( CEssNamespace* pNamespace, IWbemEventProviderRequirements* pReqSink ) { HRESULT hres;
//
// This sink owns us, so we intentionally do not AddRef it
//
m_pReqSink = pReqSink;
m_pMetaData = new CEssMetaData(pNamespace); if(m_pMetaData == NULL) return WBEM_E_OUT_OF_MEMORY; m_pMetaData->AddRef();
m_pNamespace = pNamespace; m_pNamespace->AddRef();
//
// create the pseudo proxy and sink.
//
hres = WbemCoCreateInstance( CLSID_WbemFilterProxy, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocalFilterProxy, (void**)&m_pPseudoProxy ); if( FAILED(hres) ) { return hres; } hres = m_pPseudoProxy->SetStub( &m_Stub ); if(FAILED(hres)) { return hres; } return m_pPseudoProxy->GetMainSink(&m_pPseudoSink); }
HRESULT CProviderSinkServer::GetMainProxy(IWbemEventSink** ppSink) { _DBG_ASSERT( m_pPseudoSink != NULL ); m_pPseudoSink->AddRef(); *ppSink = m_pPseudoSink; return WBEM_S_NO_ERROR; }
CProviderSinkServer::~CProviderSinkServer() { if(m_pPseudoProxy) m_pPseudoProxy->Release(); if(m_pPseudoSink) m_pPseudoSink->Release(); if(m_pMetaData) m_pMetaData->Release(); if(m_pNamespace) m_pNamespace->Release(); }
ULONG STDMETHODCALLTYPE CProviderSinkServer::AddRef() { return InterlockedIncrement(&m_lRef); }
ULONG STDMETHODCALLTYPE CProviderSinkServer::Release() { long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) delete this; return lRef; }
HRESULT STDMETHODCALLTYPE CProviderSinkServer::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown || riid == IID_IMarshal) *ppv = (IMarshal*)this; else return E_NOINTERFACE; ((IUnknown*)*ppv)->AddRef(); return S_OK; }
HRESULT STDMETHODCALLTYPE CProviderSinkServer::DeliverEvent( DWORD dwNumEvents, IWbemClassObject** apEvents, WBEM_REM_TARGETS* aTargets, CEventContext* pContext) { if(aTargets == NULL || aTargets->m_aTargets == NULL || apEvents == NULL) { ERRORTRACE((LOG_ESS, "NULL parameter received from a " "filter proxy for an event provider. Either an internal " "error has occurred, or a DENIAL OF SERVICE ATTACK has " "been thwarted\n"));
return WBEM_E_INVALID_PARAMETER; }
//
// ensure that there is no ess thread object associated with this thread.
// to avoid making the design more complicated we are not going to support
// postpone operations being used on event signaling threads. If we did
// we have to start creating thread objects and firing postponed ops on
// every event signaling - it would be rather messy and inefficient to
// say the least.
//
CEssThreadObject* pThreadObj = GetCurrentEssThreadObject();
if ( pThreadObj != NULL ) { ClearCurrentEssThreadObject(); }
for(DWORD i = 0; i < dwNumEvents; i++) { DeliverOneEvent(apEvents[i], aTargets + i, pContext); }
if ( pThreadObj != NULL ) { SetConstructedEssThreadObject( pThreadObj ); }
return WBEM_S_NO_ERROR; }
HRESULT CProviderSinkServer::DeliverOneEvent( IWbemClassObject* pEvent, WBEM_REM_TARGETS* pTargets, CEventContext* pContext ) { HRESULT hres;
_DBG_ASSERT( pContext != NULL );
if(pEvent == NULL) { ERRORTRACE((LOG_ESS, "NULL parameter received from a " "filter proxy for an event provider. Either an internal " "error has occurred, or a DENIAL OF SERVICE ATTACK has " "been thwarted\n"));
return WBEM_E_INVALID_PARAMETER; }
//
// allocate the context to be used if we need to switch to a per event
// context ( e.g. when the event has a SD ).
//
CEventContext PerEventContext; //
// take care of the event SD here. If there is an SD associated with the
// context, then we always use that one. If not, then we take the one
// associated with the event. In the latter case, it is important to
// pull the SD out here because sometimes we perform the access check
// after the SD has been projected out from the event ( this happens in
// cross-namespace subscriptions.
//
if ( pContext->GetSD() == NULL ) { ULONG cEventSD; PBYTE pEventSD = (PBYTE)GetSD( pEvent, &cEventSD );
if ( pEventSD != NULL ) { //
// must use a different context for the event,
// since it has its own SD
//
pContext = &PerEventContext;
//
// we must copy the SD here because it is not guaranteed to be
// aligned properly since it is a ptr to the direct event object
// data. The bytes MUST NOT be treated as an SD until it has
// been copied.
//
if ( !pContext->SetSD( cEventSD, pEventSD, TRUE ) ) { return WBEM_E_OUT_OF_MEMORY; } if ( !IsValidSecurityDescriptor( (PSECURITY_DESCRIPTOR)pContext->GetSD() ) ) { return WBEM_E_INVALID_OBJECT; } } } else { if ( !IsValidSecurityDescriptor( (PSECURITY_DESCRIPTOR)pContext->GetSD() ) ) { return WBEM_E_INVALID_PARAMETER; } }
//
// clone the event
//
IWbemEvent* pClone = NULL;
hres = pEvent->Clone(&pClone); if(FAILED(hres)) return hres;
CReleaseMe rm1(pClone);
if(pTargets->m_lNumTargets > 1) return MultiTargetDeliver(pClone, pTargets, pContext);
// Single target
// =============
// Check validity
// ==============
long lDestId = pTargets->m_aTargets[0]; CAbstractEventSink* pDest = NULL;
{ CInCritSec ics(&m_cs); hres = FindDestinations(1, pTargets->m_aTargets, &pDest); if(FAILED(hres)) return hres;
if(!pDest) // No longer there --- that's OK
return WBEM_S_FALSE; }
hres = pDest->Indicate(1, &pClone, pContext); pDest->Release();
return hres; }
HRESULT CProviderSinkServer::MultiTargetDeliver(IWbemEvent* pEvent, WBEM_REM_TARGETS* pTargets, CEventContext* pContext) { HRESULT hres;
// Convert the target IDs to the actual targets
// ============================================
CTempArray<CAbstractEventSink*> apSinks; if(!INIT_TEMP_ARRAY(apSinks, pTargets->m_lNumTargets)) return WBEM_E_OUT_OF_MEMORY;
{ CInCritSec ics(&m_cs); hres = FindDestinations(pTargets->m_lNumTargets, pTargets->m_aTargets, (CAbstractEventSink**)apSinks); if(FAILED(hres)) return hres; }
HRESULT hresGlobal = WBEM_S_NO_ERROR; for(int i = 0; i < pTargets->m_lNumTargets; i++) { if(apSinks[i]) { hres = apSinks[i]->Indicate(1, &pEvent, pContext); if(FAILED(hres)) hresGlobal = hres; apSinks[i]->Release(); } }
// DEBUGTRACE((LOG_ESS, "Done delivering\n"));
return hresGlobal; } // assumes: locked
HRESULT CProviderSinkServer::FindDestinations(long lNum, IN WBEM_REMOTE_TARGET_ID_TYPE* aidTargets, RELEASE_ME CAbstractEventSink** apSinks) { //
// Do a binary search for each one. The range will be getting progressively
// smaller with each element we find
//
long lLastFoundIndex = -1;
for(long i = 0; i < lNum; i++) { long lMinIndex = lLastFoundIndex+1; long lMaxIndex = m_apDestinations.GetSize() - 1; long lFound = -1; WBEM_REMOTE_TARGET_ID_TYPE idCurrent = aidTargets[i]; //
// Search the remaining portion of the array
//
while(lMinIndex <= lMaxIndex) { long lMidIndex = (lMinIndex + lMaxIndex) / 2;
WBEM_REMOTE_TARGET_ID_TYPE idMid = m_apDestinations[lMidIndex]->m_id; if(idMid == idCurrent) { lFound = lMidIndex; break; } else if(idCurrent < idMid) { lMaxIndex = lMidIndex - 1; } else { lMinIndex = lMidIndex + 1; } }
if(lFound < 0) { //
// Invalid target ID -- OK, so NULL target then
//
apSinks[i] = NULL; } else { apSinks[i] = m_apDestinations[lFound]->m_pSink; (apSinks[i])->AddRef();
//
// The rest of the IDs can only be found to the right of this one
// because the targets are sorted
//
lLastFoundIndex = lFound; } } return WBEM_S_NO_ERROR; }
HRESULT STDMETHODCALLTYPE CProviderSinkServer::DeliverStatus(long lFlags, HRESULT hresStatus, LPCWSTR wszStatus, IWbemClassObject* pErrorObj, WBEM_REM_TARGETS* pTargets, CEventContext* pContext) { return WBEM_E_UNEXPECTED; }
HRESULT STDMETHODCALLTYPE CProviderSinkServer::DeliverProviderRequest( long lFlags) { if(m_pReqSink) return m_pReqSink->DeliverProviderRequest(lFlags); else return WBEM_E_UNEXPECTED; }
// assumes: locked
HRESULT CProviderSinkServer::GetDestinations( CUniquePointerArray<CEventDestination>& apDestinations) { for(int i = 0; i < m_apDestinations.GetSize(); i++) { CEventDestination* pNew = new CEventDestination(*m_apDestinations[i]); if(pNew == NULL) return WBEM_E_OUT_OF_MEMORY; if(apDestinations.Add(pNew) < 0) { delete pNew; return WBEM_E_OUT_OF_MEMORY; } } return WBEM_S_NO_ERROR; } // assumes in m_cs;
HRESULT CProviderSinkServer::AddDestination(CAbstractEventSink* pDest, WBEM_REMOTE_TARGET_ID_TYPE* pID) { HRESULT hres = WBEM_S_NO_ERROR;
//
// Allocate a new destination ID
//
WBEM_REMOTE_TARGET_ID_TYPE idNew = m_idNext++; if(m_idNext > WBEM_MAX_FILTER_ID / 2) { //
// 32-bit integer roll-over! This provider has processed over
// 4000000000 filter creations! Canfetti is falling from the ceiling
//
DEBUGTRACE((LOG_ESS, "Filter ID rollover!!!\n"));
// BUGBUG: Postpone a call to reactivate all filters!
}
//
// Add a new destination entry
//
CEventDestination* pDestRecord = new CEventDestination(idNew, pDest); if(pDestRecord == NULL) return WBEM_E_OUT_OF_MEMORY;
m_apDestinations.Add(pDestRecord); // Record the ID in the TARGETS
// ============================
*pID = idNew; return hres; }
HRESULT CProviderSinkServer::AddFilter(LPCWSTR wszQuery, QL_LEVEL_1_RPN_EXPRESSION* pExp, CAbstractEventSink* pDest, WBEM_REMOTE_TARGET_ID_TYPE* pidRequest) { HRESULT hres; WBEM_REMOTE_TARGET_ID_TYPE idDest;
CRefedPointerArray<IWbemFilterProxy> apProxies; { CInCritSec ics(&m_cs);
// Copy proxies
// ============
if(!GetProxies(apProxies)) return WBEM_E_OUT_OF_MEMORY;
// Add to the list of destinations registered with the provider and
// construct the target identification for the proxies
// ================================================================
hres = AddDestination(pDest, &idDest); if(FAILED(hres)) return hres; } if(pidRequest) *pidRequest = idDest;
// Go through all the proxies and schedule calls
// =============================================
HRESULT hresReal = WBEM_S_NO_ERROR; for(int i = 0; i < apProxies.GetSize(); i++) { IWbemLocalFilterProxy *pLocalProxy = NULL;
// See if the proxy will allow us to call LocalAddFilter (in which case
// it's the pseudo proxy).
if (SUCCEEDED(apProxies[i]->QueryInterface( IID_IWbemLocalFilterProxy, (LPVOID*) &pLocalProxy))) { CReleaseMe rm1(pLocalProxy);
hres = pLocalProxy->LocalAddFilter( GetCurrentEssContext(), wszQuery, pExp, idDest );
hresReal = hres; // other errors do not matter
} else { hres = apProxies[i]->AddFilter( GetCurrentEssContext(), wszQuery, idDest ); }
if( FAILED(hres) ) { if ( IsRpcError(hres) ) { UnregisterProxy( apProxies[i] ); }
ERRORTRACE((LOG_ESS, "Unable to add query %S to a remote provider " "proxy. Error code: %X\n", wszQuery, hres)); } }
if ( FAILED(hresReal) ) { CInCritSec ics(&m_cs); //
// guaranteed no destinations can be added since we added the last
// one, so remove the last one.
//
m_apDestinations.RemoveAt( m_apDestinations.GetSize()-1 ); } return hresReal; }
HRESULT CProviderSinkServer::RemoveFilter(CAbstractEventSink* pDest, WBEM_REMOTE_TARGET_ID_TYPE* pidRequest) { HRESULT hres;
// Find and invalidate the filter in the list of destinations
// ==========================================================
CEventDestination* pToRemove = NULL; CRefedPointerArray<IWbemFilterProxy> apProxies;
{ CInCritSec ics(&m_cs); // Copy the proxies
// ================
if(!GetProxies(apProxies)) return WBEM_E_OUT_OF_MEMORY;
// Search for it in the array of destinations
// ==========================================
for(int i = 0; i < m_apDestinations.GetSize(); i++) { if(m_apDestinations[i]->m_pSink == pDest) { m_apDestinations.RemoveAt(i, &pToRemove); break; } }
if(pToRemove == NULL) return WBEM_E_NOT_FOUND; }
if(pidRequest) *pidRequest = pToRemove->m_id;
// The filter is invalidated, but not removed. We are outside of the CS, so
// events can be delivered (but no other changes can occur)
// =========================================================================
// Instruct all proxies to (later) remove this filter from consideration
// =====================================================================
for(int i = 0; i < apProxies.GetSize(); i++) { hres = apProxies[i]->RemoveFilter(GetCurrentEssContext(), pToRemove->m_id); if(FAILED(hres)) { if ( IsRpcError(hres) ) { UnregisterProxy( apProxies[i] ); }
ERRORTRACE((LOG_ESS, "Unable to remove filter %I64d from an event " "provider proxy: 0x%X\n", pToRemove->m_id, hres)); } }
//
// Delete the destination in question
//
delete pToRemove;
return WBEM_S_NO_ERROR; }
// assumes all proxies are locked
void CProviderSinkServer::RemoveAllFilters() { CRefedPointerArray<IWbemFilterProxy> apProxies;
{ CInCritSec ics(&m_cs); // Copy the proxies
// ================
if(!GetProxies(apProxies)) return;
//
// Clear out both the list of destinations
//
m_apDestinations.RemoveAll(); }
//
// Remove all filters from all proxies
//
for(int i = 0; i < apProxies.GetSize(); i++) { HRESULT hres = apProxies[i]->RemoveAllFilters(GetCurrentEssContext()); if(FAILED(hres)) { if ( IsRpcError(hres) ) { UnregisterProxy( apProxies[i] ); }
ERRORTRACE((LOG_ESS, "Unable to remove all queries from a " "remote provider proxy. Error code: %X\n", hres)); } }
}
//
// Only allow utilization of the guarantee if the proxy's definition
// matches the provider's definition. In other words, only when
// the provider's registration has been successfully processed,
// and the proxies are set up to reflect it, should utilization of
// the guarantee be allowed. The reason for this is that an incomplete
// source definition can cause bad things to happen when events are
// evaluated using a filter that was optimized for that definition.
//
HRESULT CProviderSinkServer::AllowUtilizeGuarantee() { CRefedPointerArray<IWbemFilterProxy> apProxies; { CInCritSec ics(&m_cs);
if ( !GetProxies( apProxies ) ) { return WBEM_E_OUT_OF_MEMORY; } }
for(int i = 0; i < apProxies.GetSize(); i++) { HRESULT hr = apProxies[i]->AllowUtilizeGuarantee();
if ( FAILED(hr) && IsRpcError(hr) ) { UnregisterProxy( apProxies[i] ); } }
return WBEM_S_NO_ERROR; } HRESULT CProviderSinkServer::AddDefinitionQuery(LPCWSTR wszQuery) { CRefedPointerArray<IWbemFilterProxy> apProxies; { CInCritSec ics(&m_cs); GetProxies(apProxies); if ( m_awsDefinitionQueries.Add(wszQuery) < 0 ) { return WBEM_E_OUT_OF_MEMORY; } }
//
// we always try to add the definition to all proxies, but if there's an
// error ( other than RPC ) we return it to the caller.
//
HRESULT hresReturn = WBEM_S_NO_ERROR;
for(int i = 0; i < apProxies.GetSize(); i++) { HRESULT hres = apProxies[i]->AddDefinitionQuery( GetCurrentEssContext(), wszQuery); if( FAILED(hres) ) { if ( IsRpcError(hres) ) { UnregisterProxy( apProxies[i] ); } else { hresReturn = hres; }
ERRORTRACE((LOG_ESS, "Unable to add definition query %S to a " "provider proxy. Error code: %X\n", wszQuery, hres)); } }
return hresReturn; }
// assumes: all proxies are locked
void CProviderSinkServer::RemoveAllDefinitionQueries() { CInCritSec ics(&m_cs);
m_awsDefinitionQueries.Empty();
for(int i = 0; i < m_apProxies.GetSize(); i++) { HRESULT hres = m_apProxies[i]->RemoveAllDefinitionQueries( GetCurrentEssContext()); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to remove all definition queries from" " a provider proxy. Error code: %X\n", hres)); } } }
void CProviderSinkServer::Clear() { // Provider is being removed. First, we disconnect all proxies, ensuring
// that no more events are delivered
// ======================================================================
CRefedPointerArray<IWbemFilterProxy> apProxies; { CInCritSec ics(&m_cs); GetProxies(apProxies); m_apProxies.RemoveAll(); m_awsDefinitionQueries.Empty(); }
//
// since we are going to disconnect the proxy it is illegal to own the
// namespace lock. Reason is that disconnecting takes ownership of the
// proxy lock.
//
_DBG_ASSERT( !m_pNamespace->DoesThreadOwnNamespaceLock() );
for(int i = 0; i < apProxies.GetSize(); i++) { apProxies[i]->Disconnect(); }
// Now we clean up
// ===============
RemoveAllFilters(); RemoveAllDefinitionQueries();
m_pReqSink = NULL;
CWbemPtr<IUnknown> pStubUnk;
HRESULT hr = m_Stub.QueryInterface( IID_IUnknown, (void**)&pStubUnk );
_DBG_ASSERT( SUCCEEDED(hr) );
hr = CoDisconnectObject( pStubUnk, 0 );
if ( FAILED( hr ) ) { ERRORTRACE((LOG_ESS,"Failed Disconnecting Stub.\n")); } }
HRESULT CProviderSinkServer::Lock() { //
// it is illegal to lock proxies while holding the namespace lock.
//
_DBG_ASSERT( !m_pNamespace->DoesThreadOwnNamespaceLock() );
// DEBUGTRACE((LOG_ESS, "Server %p locking all proxies\n", this));
// First we lock all the proxies. In the interim, events are still
// delivered. Once done, events are blocked in proxies
// ================================================================
CRefedPointerArray<IWbemFilterProxy> apProxies; { CInCritSec ics(&m_cs); //
// First, check if we are already locked. If so, no need to bother
// the proxies. Not only that, but since proxies are out-of-proc, we
// would be re-locking them on a different thread, causing a deadlock.
//
if(m_lLocks++ > 0) return WBEM_S_NO_ERROR;
GetProxies(apProxies); }
for(int i = 0; i < apProxies.GetSize(); i++) { // DEBUGTRACE((LOG_ESS, "Server %p locking proxy %p\n", this,
// apProxies[i]));
HRESULT hres = apProxies[i]->Lock();
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to lock a remote provider proxy. " "Error code: %X\n", hres)); //
// if we couldn't lock it because of an RPC Error, simply
// unregister, else we have big problems and should unlock all
// the proxies and return the error.
//
if ( IsRpcError( hres ) ) { UnregisterProxy( apProxies[i] ); } else { for(int j = 0; j < i; j++) apProxies[j]->Unlock(); return hres; } } }
return WBEM_S_NO_ERROR; }
BOOL CProviderSinkServer::GetProxies( CRefedPointerArray<IWbemFilterProxy>& apProxies) { CInCritSec ics(&m_cs);
for(int i = 0; i < m_apProxies.GetSize(); i++) { if(apProxies.Add(m_apProxies[i]) < 0) return FALSE; }
return TRUE; }
void CProviderSinkServer::Unlock() { // DEBUGTRACE((LOG_ESS, "Server %p unlocking all proxies\n", this));
CRefedPointerArray<IWbemFilterProxy> apProxies; { CInCritSec ics(&m_cs); //
// First, check if this is the last unlock. If not, we didn't forward
// this lock, so we shouldn't forward this unlock either
//
if(--m_lLocks != 0) return;
GetProxies(apProxies); }
for(int i = 0; i < apProxies.GetSize(); i++) { // DEBUGTRACE((LOG_ESS, "Server %p unlocking proxy %p\n", this,
// apProxies[i]));
HRESULT hres = apProxies[i]->Unlock(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to unlock a remote provider proxy. " "Error code: %X\n", hres)); if ( IsRpcError(hres) ) { UnregisterProxy( apProxies[i] ); } } } }
HRESULT STDMETHODCALLTYPE CProviderSinkServer::RegisterProxy( IWbemFilterProxy* pProxy) { // Initialize it with ourselves
// ============================
HRESULT hres = pProxy->Initialize(m_pMetaData, &m_Stub); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to initialize remote proxy: %X\n", hres)); return hres; }
//
// aquire ns lock here because we need to ensure that we have a
// consistent set of definition queries and filters to initialize the
// proxy with. The cs member of this class is not good enough by
// itself because definition queries and filters are all manipulated
// separately but are always consistent outside of a ess namespace
// operation - which is why we grab the ns lock. It is likely that
// the provider lock is held in this control path already, but it is
// allowed for provider lock to be held when aquiring the ns lock (
// but not the other way around ). We need to ensure that the
// update lock is ALWAYS aquired before the cs to avoid deadlocks.
// Furthermore, we need to hold the lock while populating the provider
// with the filters. This is consistent with all other modifications to
// the provider's filter.
//
CInUpdate iu( m_pNamespace );
{ CInCritSec ics(&m_cs); if(m_apProxies.Add(pProxy) < 0) return WBEM_E_OUT_OF_MEMORY; }
//
// Add all the definition queries to this proxy
//
int i; BOOL bUtilizeGuarantee = TRUE; for(i = 0; i < m_awsDefinitionQueries.Size(); i++) { hres = pProxy->AddDefinitionQuery( GetCurrentEssContext(), m_awsDefinitionQueries[i]);
if(FAILED(hres)) { //
// TODO : We need to mark the provider as inactive.
//
ERRORTRACE((LOG_ESS, "Unable to add definition query '%S' to " "provider sink: 0x%X.\n", m_awsDefinitionQueries[i], hres)); bUtilizeGuarantee = FALSE; } }
if ( bUtilizeGuarantee ) { pProxy->AllowUtilizeGuarantee(); } //
// Add all the filters to this proxy
//
for(i = 0; i < m_apDestinations.GetSize(); i++) { // Retrieve the filter from the event sink
// =======================================
CEventDestination* pDest = m_apDestinations[i]; CEventFilter* pFilter = pDest->m_pSink->GetEventFilter(); if(pFilter == NULL) { ERRORTRACE((LOG_ESS, "Internal error: non-filter sink in " "proxy\n")); continue; }
LPWSTR wszQuery; LPWSTR wszQueryLanguage; BOOL bExact; if(SUCCEEDED(pFilter->GetCoveringQuery(wszQueryLanguage, wszQuery, bExact, NULL)) && bExact) { // Add this filter to this proxy
// =============================
hres = pProxy->AddFilter(GetCurrentEssContext(), wszQuery, pDest->m_id);
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to add query %S to a remote " "provider proxy. Error code: %X\n", wszQuery, hres)); }
delete [] wszQuery; delete [] wszQueryLanguage; } }
return WBEM_S_NO_ERROR; }
HRESULT STDMETHODCALLTYPE CProviderSinkServer::UnregisterProxy( IWbemFilterProxy* pProxy) { CInCritSec ics(&m_cs);
// Look for it
// ===========
for(int i = 0; i < m_apProxies.GetSize(); i++) { if(m_apProxies[i] == pProxy) { // It is safe to release it, since the caller has a ref-count
// ==========================================================
m_apProxies.RemoveAt(i); return WBEM_S_NO_ERROR; } }
return WBEM_S_FALSE; }
ULONG STDMETHODCALLTYPE CFilterStub::AddRef() { return m_pSink->AddRef(); }
ULONG STDMETHODCALLTYPE CFilterStub::Release() { return m_pSink->Release(); }
HRESULT STDMETHODCALLTYPE CFilterStub::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown || riid == IID_IWbemFilterStub) { *ppv = (IWbemFilterStub*)this; } else if(riid == IID_IWbemMultiTarget) { *ppv = (IWbemMultiTarget*)this; } else if ( riid == IID_IWbemFetchSmartMultiTarget ) { *ppv = (IWbemFetchSmartMultiTarget*)this; } else if ( riid == IID_IWbemSmartMultiTarget ) { *ppv = (IWbemSmartMultiTarget*)this; } else if( riid == IID_IWbemEventProviderRequirements) { *ppv = (IWbemEventProviderRequirements*)this; } else return E_NOINTERFACE;
AddRef(); return S_OK; }
HRESULT STDMETHODCALLTYPE CFilterStub::RegisterProxy(IWbemFilterProxy* pProxy) { return m_pSink->RegisterProxy(pProxy); }
HRESULT STDMETHODCALLTYPE CFilterStub::UnregisterProxy(IWbemFilterProxy* pProxy) { return m_pSink->UnregisterProxy(pProxy); }
HRESULT STDMETHODCALLTYPE CFilterStub::DeliverEvent(DWORD dwNumEvents, IWbemClassObject** apEvents, WBEM_REM_TARGETS* aTargets, long lSDLength, BYTE* pSD) { CEventContext Context; Context.SetSD( lSDLength, pSD, FALSE ); return m_pSink->DeliverEvent( dwNumEvents, apEvents, aTargets, &Context ); }
HRESULT STDMETHODCALLTYPE CFilterStub::DeliverStatus(long lFlags, HRESULT hresStatus, LPCWSTR wszStatus, IWbemClassObject* pErrorObj, WBEM_REM_TARGETS* pTargets, long lSDLength, BYTE* pSD) { CEventContext Context; Context.SetSD( lSDLength, pSD, FALSE ); return m_pSink->DeliverStatus(lFlags, hresStatus, wszStatus, pErrorObj, pTargets, &Context); }
HRESULT STDMETHODCALLTYPE CFilterStub::DeliverProviderRequest(long lFlags) { return m_pSink->DeliverProviderRequest(lFlags); }
HRESULT STDMETHODCALLTYPE CFilterStub::GetSmartMultiTarget( IWbemSmartMultiTarget** ppSmartMultiTarget ) { return QueryInterface( IID_IWbemSmartMultiTarget, (void**) ppSmartMultiTarget );
}
HRESULT STDMETHODCALLTYPE CFilterStub::DeliverEvent(ULONG dwNumEvents, ULONG dwBuffSize, BYTE* pBuffer, WBEM_REM_TARGETS* pTargets, long lSDLength, BYTE* pSD) {
// Unwind the buffer into an object. Note that because m_ClassCache is
// STL based, it is intrinsically thread-safe. Also, calling proxies are
// serialized, so we shouldn't have any thread-safety problems here.
CWbemMtgtDeliverEventPacket packet( (LPBYTE) pBuffer, dwBuffSize ); long lObjectCount; IWbemClassObject ** pObjArray; HRESULT hr = packet.UnmarshalPacket( lObjectCount, pObjArray, m_ClassCache );
if ( SUCCEEDED( hr ) ) { // Number must be dwNumEvents
if(lObjectCount == dwNumEvents) { // Now call the standard deliver event function and hand it the
// object
hr = DeliverEvent(dwNumEvents, pObjArray, pTargets, lSDLength, pSD); } else { hr = WBEM_E_UNEXPECTED; }
// Release the objects in the array and clean up pObjArray
for ( int lCtr = 0; lCtr < lObjectCount; lCtr++ ) { pObjArray[lCtr]->Release(); }
delete [] pObjArray;
} // IF UnmarshalPacket
return hr; }
void CProviderSinkServer::GetStatistics(long* plProxies, long* plDestinations, long* plFilters, long* plTargetLists, long* plTargets, long* plPostponed) { *plProxies = m_apProxies.GetSize(); *plDestinations = m_apDestinations.GetSize();
/* BUGBUG: do properly for all sinks
((CFilterProxy*)m_pSink)->GetStatistics(plFilters, plTargetLists, plTargets, plPostponed); */ }
//******************************************************************************
//******************************************************************************
//
// CRECORD :: CQUERY RECORD
//
//******************************************************************************
//******************************************************************************
CEventProviderCache::CRecord::CQueryRecord::CQueryRecord() : m_strQuery(NULL), m_pEventClass(NULL), m_dwEventMask(0), m_paInstanceClasses(NULL), m_pExpr(NULL) { }
HRESULT CEventProviderCache::CRecord::CQueryRecord::EnsureClasses( CEssNamespace* pNamespace ) { HRESULT hres = WBEM_S_NO_ERROR;
_IWmiObject* pClass;
if ( m_pEventClass == NULL ) { if ( SUCCEEDED( pNamespace->GetClass( m_pExpr->bsClassName, &pClass ) ) ) { m_pEventClass = pClass; } else { hres = WBEM_S_FALSE; } }
if ( m_paInstanceClasses != NULL ) { for(int i = 0; i < m_paInstanceClasses->GetNumClasses(); i++) { CClassInformation* pInfo = m_paInstanceClasses->GetClass(i);
if ( pInfo->m_pClass == NULL ) { if ( SUCCEEDED( pNamespace->GetClass( pInfo->m_wszClassName, &pClass) ) ) { pInfo->m_pClass = pClass; } else { hres = WBEM_S_FALSE; } } } } else { hres = WBEM_S_FALSE; } return hres; }
void CEventProviderCache::CRecord::CQueryRecord::ReleaseClasses() { if ( m_pEventClass != NULL ) { m_pEventClass->Release(); m_pEventClass = NULL; }
if ( m_paInstanceClasses != NULL ) { for(int i = 0; i < m_paInstanceClasses->GetNumClasses(); i++) { CClassInformation* pInfo = m_paInstanceClasses->GetClass(i);
if ( pInfo->m_pClass != NULL ) { pInfo->m_pClass->Release(); pInfo->m_pClass = NULL; } } } }
HRESULT CEventProviderCache::CRecord::CQueryRecord::Initialize( LPCWSTR wszQuery, LPCWSTR wszProvName, CEssNamespace* pNamespace, bool bSystem) { HRESULT hres;
m_strQuery = SysAllocString(wszQuery); if(m_strQuery == NULL) return WBEM_E_OUT_OF_MEMORY;
// Parse the query
// ===============
CTextLexSource Source((LPWSTR)wszQuery); QL1_Parser Parser(&Source); if(Parser.Parse(&m_pExpr) != QL1_Parser::SUCCESS) { ERRORTRACE((LOG_ESS, "Invalid query in provider registration: %S\n", wszQuery));
CEventLog Log; Log.Open(); Log.Report(EVENTLOG_ERROR_TYPE, WBEM_MC_INVALID_EVENT_PROVIDER_QUERY, wszQuery); return WBEM_E_UNPARSABLE_QUERY; }
if(!bSystem) { if(!wbem_wcsicmp(m_pExpr->bsClassName, L"__Event") || !wbem_wcsicmp(m_pExpr->bsClassName, L"__ExtrinsicEvent")) { ERRORTRACE((LOG_ESS, "Provider claims to provide all events with " "query: %S\n" "We don't believe it, so we ignore the registration\n\n", wszQuery)); CEventLog Log; Log.Open(); Log.Report(EVENTLOG_ERROR_TYPE, WBEM_MC_EVENT_PROVIDER_QUERY_TOO_BROAD, wszQuery); return WBEMESS_E_REGISTRATION_TOO_BROAD; } }
// Determine its event mask
// ========================
m_dwEventMask = CEventRepresentation::GetTypeMaskFromName( m_pExpr->bsClassName);
// Check if the mask mentions any pollable events
// ==============================================
if(m_dwEventMask & INTRINSIC_EVENTS_MASK) { // Yes. Get instance classes for which it providers these events
// =============================================================
hres = CQueryAnalyser::GetDefiniteInstanceClasses(m_pExpr, m_paInstanceClasses);
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to determine instance classes for which events" "are provided by this query: %S\n", wszQuery));
CEventLog Log; Log.Open(); Log.Report(EVENTLOG_ERROR_TYPE, WBEM_MC_INVALID_EVENT_PROVIDER_INTRINSIC_QUERY, wszQuery); return WBEM_E_UNINTERPRETABLE_PROVIDER_QUERY; }
if(!bSystem && !m_paInstanceClasses->IsLimited()) { ERRORTRACE((LOG_ESS, "Provider claims to provide all intrinsic events with " "query: %S\n" "We don't believe it, so we ignore the registration\n\n", wszQuery));
CEventLog Log; Log.Open(); Log.Report(EVENTLOG_ERROR_TYPE, WBEM_MC_EVENT_PROVIDER_QUERY_TOO_BROAD, wszQuery); return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Get the actual classes from the namespace
// =========================================
for(int i = 0; i < m_paInstanceClasses->GetNumClasses(); i++) { CClassInformation* pInfo = m_paInstanceClasses->GetClass(i); _IWmiObject* pClass = NULL; hres = pNamespace->GetClass(pInfo->m_wszClassName, &pClass); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Could not get class %S for which provider claims" " to provider events. Error code: %X\n", pInfo->m_wszClassName, hres));
CEventLog Log; Log.Open(); Log.Report(EVENTLOG_ERROR_TYPE, WBEM_MC_EVENT_PROVIDER_QUERY_NOT_FOUND, wszQuery, pInfo->m_wszClassName);
//
// Before continuing, we register for class creation event on
// this class. This way, when it is finally created, we will
// reactivate stuff and bring the system back on track
//
hres = pNamespace->RegisterProviderForClassChanges( pInfo->m_wszClassName, wszProvName );
// ignore error code --- what can we do?
return WBEM_S_FALSE; } //
// don't store, we'll retrieve it later as necessary. This
// will require that the user call EnsureClasses() before calling
// any function that needs those classes.
//
pClass->Release(); } } // Get the event class
// ===================
_IWmiObject* pClass = NULL; hres = pNamespace->GetClass(m_pExpr->bsClassName, &pClass);
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Invalid event class %S in provider registration \n" "Query was: %S\n\n", m_pExpr->bsClassName, wszQuery));
CEventLog Log; Log.Open(); Log.Report(EVENTLOG_ERROR_TYPE, WBEM_MC_EVENT_PROVIDER_QUERY_NOT_FOUND, wszQuery, m_pExpr->bsClassName);
//
// Before continuing, we register for class creation event on this
// class. This way, when it is finally created, we will reactivate
// stuff and bring the system back on track
//
hres = pNamespace->RegisterProviderForClassChanges( m_pExpr->bsClassName, wszProvName ); // ignore error code --- what can we do?
return WBEM_S_FALSE; }
//
// don't store, we'll retrieve it later as necessary. This
// will require that the user call EnsureClasses() before calling
// any function that needs those classes.
//
CReleaseMe rmpClass( pClass );
if( pClass->InheritsFrom(L"__Event") != S_OK) { ERRORTRACE((LOG_ESS, "Invalid event class %S in provider registration \n" "Query was: %S\n\n", m_pExpr->bsClassName, wszQuery));
CEventLog Log; Log.Open(); Log.Report(EVENTLOG_ERROR_TYPE, WBEM_MC_EVENT_PROVIDER_QUERY_NOT_EVENT, wszQuery, m_pExpr->bsClassName); return WBEM_S_FALSE; }
return WBEM_S_NO_ERROR; } CEventProviderCache::CRecord::CQueryRecord::~CQueryRecord() { SysFreeString(m_strQuery); if(m_pEventClass) m_pEventClass->Release(); delete m_paInstanceClasses; delete m_pExpr; }
HRESULT CEventProviderCache::CRecord::CQueryRecord::Update(LPCWSTR wszClassName, IWbemClassObject* pClass) { HRESULT hres = WBEM_S_FALSE;
// Check the event class
// =====================
if(!wbem_wcsicmp(wszClassName, m_pExpr->bsClassName)) { if(pClass == NULL) { // This query record is hereby invalid
// ===================================
ERRORTRACE((LOG_ESS, "Event provider query, %S, is invalidated by class " "deletion of %S\n", m_strQuery, m_pExpr->bsClassName));
if(m_pEventClass) m_pEventClass->Release(); m_pEventClass = NULL; delete m_paInstanceClasses; m_paInstanceClasses = NULL; } else { // Change the class definition
// ===========================
if(m_pEventClass) { m_pEventClass->Release(); m_pEventClass = NULL; hres = pClass->Clone(&m_pEventClass); if ( FAILED(hres) ) return hres; } }
hres = WBEM_S_NO_ERROR; } if(m_paInstanceClasses) { // Check the instance classes
// ==========================
for(int i = 0; i < m_paInstanceClasses->GetNumClasses(); i++) { CClassInformation* pInfo = m_paInstanceClasses->GetClass(i); if(!wbem_wcsicmp(wszClassName, pInfo->m_wszClassName)) { if(pClass) { // This class is no longer there
// =============================
ERRORTRACE((LOG_ESS, "Class %S for which provider claims to provide" " events is deleted", pInfo->m_wszClassName));
m_paInstanceClasses->RemoveClass(i); i--; } else { // Change the class definition
// ===========================
if(pInfo->m_pClass) { pInfo->m_pClass->Release(); pInfo->m_pClass = NULL; hres = pClass->Clone(&pInfo->m_pClass); if ( FAILED(hres) ) return hres; } } hres = WBEM_S_NO_ERROR; } } }
return hres; } HRESULT CEventProviderCache::CRecord::CQueryRecord::DoesIntersectWithQuery( IN CRequest& Request, CEssNamespace* pNamespace) { HRESULT hres;
if(m_pEventClass == NULL) { // Inactive record
return WBEM_S_FALSE; }
// Check that the classes are related --- one is derived from another
// ==================================================================
if(m_pEventClass->InheritsFrom(Request.GetQueryExpr()->bsClassName) != WBEM_S_NO_ERROR && Request.GetEventClass(pNamespace)->InheritsFrom(m_pExpr->bsClassName) != WBEM_S_NO_ERROR ) { // Not the right class.
// ====================
return WBEM_S_FALSE; }
// For extrinsic providers, this is good enough. But for
// intrinsic providers, we need to check if the requested
// instance classes intersect with the provided ones
// ======================================================
if(Request.GetEventMask() & INSTANCE_EVENTS_MASK) { INTERNAL CClassInfoArray* pClasses = NULL; hres = Request.GetInstanceClasses(pNamespace, &pClasses); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Failed to determine instance classes required by query '%S':" "0x%X\n", Request.GetQuery(), hres)); return hres; }
if(!CQueryAnalyser::CompareRequestedToProvided( *pClasses, *m_paInstanceClasses)) { // This intrinsic provider does not need activation
// ================================================
return WBEM_S_FALSE; } }
// All test have been passed
// =========================
return WBEM_S_NO_ERROR; }
DWORD CEventProviderCache::CRecord::CQueryRecord::GetProvidedEventMask( IWbemClassObject* pClass, BSTR strClassName) { if(m_pEventClass == NULL || m_paInstanceClasses == NULL) { // Not active as an intrinsic provider record
// ==========================================
return 0; }
// Check that we supply intrinsic events
// =====================================
if((m_dwEventMask & INSTANCE_EVENTS_MASK) == 0) return 0;
// Go through all the instance classes for which it provides events
// ================================================================
for(int k = 0; k < m_paInstanceClasses->GetNumClasses(); k++) { CClassInformation* pInfo = m_paInstanceClasses->GetClass(k); if(pInfo->m_pClass == NULL) { // Non-existent class
// ==================
return 0; }
//
// If desired class is derived from the provided class, then we are
// covered. If it is the other way around, we are not
//
if(pClass->InheritsFrom(pInfo->m_wszClassName) == S_OK) return m_dwEventMask; }
return 0; } //******************************************************************************
//******************************************************************************
//
// CRECORD
//
//******************************************************************************
//******************************************************************************
CEventProviderCache::CRecord::CRecord() : m_strName(NULL), m_lRef(0), m_bStarted(false), m_lPermUsageCount(0), m_bProviderSet(FALSE), m_lUsageCount(0), m_pProvider(NULL), m_pQuerySink(NULL), m_pMainSink(NULL), m_pSecurity(NULL), m_LastUse(CWbemTime::GetCurrentTime()), m_bRecorded(FALSE), m_bNeedsResync(TRUE), m_strNamespace(NULL) { }
HRESULT CEventProviderCache::CRecord::Initialize( LPCWSTR wszName, CEssNamespace* pNamespace ) { m_pNamespace = pNamespace; m_pNamespace->AddRef();
m_pMainSink = new CProviderSinkServer(); if(m_pMainSink == NULL) return WBEM_E_OUT_OF_MEMORY; m_pMainSink->AddRef();
m_strNamespace = SysAllocString(pNamespace->GetName()); if(m_strNamespace == NULL) return WBEM_E_OUT_OF_MEMORY;
if ( wszName != NULL ) { m_strName = SysAllocString(wszName); if(m_strName == NULL) return WBEM_E_OUT_OF_MEMORY; }
return m_pMainSink->Initialize(pNamespace, this); }
CEventProviderCache::CRecord::~CRecord() { if(m_pNamespace) m_pNamespace->Release();
if( m_pMainSink ) { //
// shutdown and release the sink server. We must postpone the
// shutdown though because it will release any outstanding
// proxies which cannot be done while holding the namespace lock.
//
CPostponedList* pList = GetCurrentPostponedList();
_DBG_ASSERT( pList != NULL );
CPostponedSinkServerShutdown* pReq;
pReq = new CPostponedSinkServerShutdown( m_pMainSink );
if ( pReq != NULL ) { if ( FAILED(pList->AddRequest( m_pNamespace, pReq ) ) ) { delete pReq; } }
m_pMainSink->Release(); }
UnloadProvider();
SysFreeString(m_strNamespace); SysFreeString(m_strName); }
ULONG CEventProviderCache::CRecord::AddRef() { return InterlockedIncrement(&m_lRef); }
ULONG CEventProviderCache::CRecord::Release() { long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) delete this; return lRef; }
BOOL CEventProviderCache::CRecord::IsEmpty() { return ( !m_bProviderSet && m_apQueries.GetSize() == 0); }
HRESULT CEventProviderCache::CRecord::SetProvider(IWbemClassObject* pWin32Prov) { HRESULT hres;
// Clean out the old data
// ======================
m_bProviderSet = FALSE;
VARIANT v; VariantInit(&v); CClearMe cm1(&v);
// Verity object validity
// ======================
if(pWin32Prov->InheritsFrom(WIN32_PROVIDER_CLASS) != WBEM_S_NO_ERROR) return WBEM_E_INVALID_PROVIDER_REGISTRATION;
// removed doublecheck - a decoupled provider does not have a clsid
// if(FAILED(pWin32Prov->Get(PROVIDER_CLSID_PROPNAME, 0, &v, NULL, NULL)) ||
// V_VT(&v) != VT_BSTR)
// return WBEM_E_INVALID_PROVIDER_REGISTRATION;
if(m_pProvider) { UnloadProvider(); }
// Store object for later use
// ==========================
m_bProviderSet = TRUE;
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::ResetProvider() { if(m_bProviderSet) { m_bProviderSet = FALSE; return WBEM_S_NO_ERROR; } else { return WBEM_S_FALSE; } }
HRESULT CEventProviderCache::CRecord::GetProviderInfo( IWbemClassObject* pRegistration, BSTR& strName) { VARIANT v; VariantInit(&v); strName = NULL;
if(FAILED(pRegistration->Get(PROVIDER_NAME_PROPNAME, 0, &v, NULL, NULL)) || V_VT(&v) != VT_BSTR) { return WBEM_E_INVALID_PROVIDER_REGISTRATION; }
strName = V_BSTR(&v); // VARIANT intentionally not cleared
return WBEM_S_NO_ERROR; } HRESULT CEventProviderCache::CRecord::GetRegistrationInfo( IWbemClassObject* pRegistration, BSTR& strName) { VARIANT v; VariantInit(&v); CClearMe cm1(&v); strName = NULL;
if(FAILED(pRegistration->Get(EVPROVREG_PROVIDER_REF_PROPNAME, 0, &v, NULL, NULL)) || V_VT(&v) != VT_BSTR) { ERRORTRACE((LOG_ESS, "NULL provider reference in event provider " "registration! Registration is invalid\n")); return WBEM_E_INVALID_PROVIDER_REGISTRATION; }
// Parse the path
// ==============
CObjectPathParser Parser; ParsedObjectPath* pPath; int nRes = Parser.Parse(V_BSTR(&v), &pPath); if(nRes != CObjectPathParser::NoError) { ERRORTRACE((LOG_ESS, "Unparsable provider reference in event provider " "registration: %S. Registration is invalid\n", V_BSTR(&v))); return WBEM_E_INVALID_PROVIDER_REGISTRATION; }
//
// It would be good to check that the class specified here is valid, but
// we cannot just compare the name since this may be a derived class of
// __Win32Provider. And getting the class definition and comparing would
// be too expensive, so we'll just trust the provider here
//
//
// if(wbem_wcsicmp(pPath->m_pClass, WIN32_PROVIDER_CLASS))
// {
// Parser.Free(pPath);
// return WBEM_E_INVALID_PROVIDER_REGISTRATION;
// }
if(pPath->m_dwNumKeys != 1) { Parser.Free(pPath); ERRORTRACE((LOG_ESS, "Wrong number of keys in provider reference in " "event provider registration: %S. Registration is invalid\n", V_BSTR(&v))); return WBEM_E_INVALID_PROVIDER_REGISTRATION; }
if(V_VT(&pPath->m_paKeys[0]->m_vValue) != VT_BSTR) { Parser.Free(pPath); ERRORTRACE((LOG_ESS, "Wrong key type in provider reference in event " "provider registration: %S. Registration is invalid\n", V_BSTR(&v))); return WBEM_E_INVALID_PROVIDER_REGISTRATION; }
strName = SysAllocString(V_BSTR(&pPath->m_paKeys[0]->m_vValue)); Parser.Free(pPath);
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::SetQueries(CEssNamespace* pNamespace, IWbemClassObject* pRegistration) { HRESULT hres; // Get the list of class names
// ===========================
VARIANT v; VariantInit(&v);
if(FAILED(pRegistration->Get(EVPROVREG_QUERY_LIST_PROPNAME, 0, &v, NULL, NULL)) || V_VT(&v) != (VT_BSTR | VT_ARRAY)) { ResetQueries(); return WBEM_E_INVALID_PROVIDER_REGISTRATION; } CClearMe cm(&v);
SAFEARRAY* psa = V_ARRAY(&v); long lLBound, lUBound; SafeArrayGetLBound(psa, 1, &lLBound); SafeArrayGetUBound(psa, 1, &lUBound); long lElements = lUBound - lLBound + 1;
BSTR* astrQueries; SafeArrayAccessData(psa, (void**)&astrQueries); CUnaccessMe um(psa); return SetQueries(pNamespace, lElements, (LPCWSTR*)astrQueries); }
HRESULT CEventProviderCache::CRecord::SetQueries(CEssNamespace* pNamespace, long lNumQueries, LPCWSTR* awszQueries) { HRESULT hres;
ResetQueries();
// Create a record for each query
// ==============================
BOOL bUtilizeGuarantee = TRUE;
for(long lQueryIndex = 0; lQueryIndex < lNumQueries; lQueryIndex++) { hres = AddDefinitionQuery(pNamespace, awszQueries[lQueryIndex]);
if ( FAILED(hres) ) { bUtilizeGuarantee = FALSE; } if( hres == WBEM_E_OUT_OF_MEMORY ) { return hres; } }
if ( bUtilizeGuarantee ) { m_pMainSink->AllowUtilizeGuarantee(); }
return WBEM_S_NO_ERROR; }
// assumes: CProviderSinkServer locked!
HRESULT CEventProviderCache::CRecord::AddDefinitionQuery( CEssNamespace* pNamespace, LPCWSTR wszQuery) { HRESULT hres;
CQueryRecord* pNewQueryRecord = new CQueryRecord; if(pNewQueryRecord == NULL) return WBEM_E_OUT_OF_MEMORY;
hres = pNewQueryRecord->Initialize( wszQuery, m_strName, pNamespace, IsSystem()); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Skipping provider %S invalid registration query %S\n", m_strName, wszQuery)); } else { hres = m_pMainSink->AddDefinitionQuery(wszQuery); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Skipping provider %S registration query %S\n" " failed to merge: %X\n", m_strName, wszQuery, hres)); } if(m_apQueries.Add(pNewQueryRecord) < 0) { delete pNewQueryRecord; hres = WBEM_E_OUT_OF_MEMORY; } }
return hres; }
HRESULT CEventProviderCache::CRecord::ResetQueries() { m_apQueries.RemoveAll(); m_pMainSink->RemoveAllDefinitionQueries(); return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::PostponeNewQuery(CExecLine::CTurn* pTurn, DWORD dwId, LPCWSTR wszQueryLanguage, LPCWSTR wszQuery, CAbstractEventSink* pDest) { CPostponedList* pList = GetCurrentPostponedList(); //
// if null, then no thread object associated with thread. caller may
// need to use an CEssInternalOperationSink.
//
_DBG_ASSERT( pList != NULL );
CPostponedNewQuery* pReq = new CPostponedNewQuery(this, dwId, wszQueryLanguage, wszQuery, pTurn, pDest); if(pReq == NULL) { return WBEM_E_OUT_OF_MEMORY; } HRESULT hr = pList->AddRequest( m_pNamespace, pReq);
if ( FAILED(hr) ) { delete pReq; return hr; }
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::PostponeCancelQuery( CExecLine::CTurn* pTurn, DWORD dwId) { CPostponedList* pList = GetCurrentPostponedList(); //
// if null, then no thread object associated with thread. caller may
// need to use an CEssInternalOperationSink.
//
_DBG_ASSERT( pList != NULL ); CPostponedCancelQuery* pReq = new CPostponedCancelQuery(this, pTurn, dwId); if( pReq == NULL ) { return WBEM_E_OUT_OF_MEMORY; }
HRESULT hr = pList->AddRequest( m_pNamespace, pReq );
if ( FAILED(hr) ) { delete pReq; return hr; }
return WBEM_S_NO_ERROR; }
// assumes: no locks are held
HRESULT CEventProviderCache::CRecord::Exec_LoadProvider( CEssNamespace* pNamespace) { HRESULT hres;
// Having locked the namespace, retrieve the necessary parameters
// ==============================================================
CLSID clsid;
IWbemObjectSink* pEventSink = NULL; { CInUpdate iu(pNamespace);
if(pNamespace->IsShutdown()) return WBEM_E_INVALID_NAMESPACE;
// Check if it is already loaded
// =============================
if(m_pProvider) return WBEM_S_FALSE; }
IWbemEventProvider* pProvider = NULL; hres = m_pNamespace->LoadEventProvider(m_strName, &pProvider); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to load event provider '%S' in namespace " "'%S': 0x%X\n", m_strName, m_pNamespace->GetName(), hres)); return hres; } CReleaseMe rm1(pProvider);
/* TAKEN CARE OF BY THE PROVSS
//
// In case this is a "framework" provider, inform it of its registration
//
IWbemProviderIdentity* pIdent = NULL; hres = pProvider->QueryInterface(IID_IWbemProviderIdentity, (void**)&pIdent); if(SUCCEEDED(hres)) { CReleaseMe rm(pIdent); hres = pIdent->SetRegistrationObject(0, m_pWin32Prov);
if(hres == WBEM_E_PROVIDER_NOT_CAPABLE) hres = WBEM_S_SUBJECT_TO_SDS;
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Event provider %S failed to accept its " "registration object with error code 0x%X\n", m_strName, hres)); return hres; } } */
//
// Deposit this and other provider pointers into the record
//
hres = SetProviderPointer(pNamespace, pProvider); if(FAILED(hres)) return hres;
//
// Report the MSFT_WmiEventProviderLoaded event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiEventProviderLoaded], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
pNamespace->GetName(), m_strName);
//
// Postpone start until all activations are done
//
CPostponedList* pList = GetCurrentPostponedList(); //
// if null, then no thread object associated with thread. caller may
// need to use an CEssInternalOperationSink.
//
_DBG_ASSERT( pList != NULL ); CPostponedProvideEvents* pReq = new CPostponedProvideEvents(this); if(pReq == NULL) { return WBEM_E_OUT_OF_MEMORY; }
hres = pList->AddRequest( m_pNamespace, pReq);
if ( FAILED(hres) ) { delete pReq; } return hres; }
HRESULT CEventProviderCache::CRecord::SetProviderPointer( CEssNamespace* pNamespace, IWbemEventProvider* pProvider) { HRESULT hres;
//
// Check the "smart provider" interface
//
IWbemEventProviderQuerySink* pQuerySink = NULL; hres = pProvider->QueryInterface(IID_IWbemEventProviderQuerySink, (void**)&pQuerySink); CReleaseMe rm4(pQuerySink);
//
// Check the security interface
//
IWbemEventProviderSecurity* pSecurity = NULL; hres = pProvider->QueryInterface(IID_IWbemEventProviderSecurity, (void**)&pSecurity); CReleaseMe rm5(pSecurity);
// Having locked the namespace, deposit the pointers into the record
// =================================================================
{ CInUpdate iu(pNamespace);
if(pNamespace->IsShutdown()) return WBEM_E_INVALID_NAMESPACE;
m_pProvider = pProvider; pProvider->AddRef(); m_pQuerySink = pQuerySink; if(pQuerySink) pQuerySink->AddRef();
m_pSecurity = pSecurity; if(pSecurity) pSecurity->AddRef(); }
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::Exec_StartProvider( CEssNamespace* pNamespace) { IWbemEventProvider* pProvider = NULL; IWbemEventSink* pEventSink = NULL; HRESULT hres;
{ CInUpdate iu(pNamespace);
if(m_bStarted) return WBEM_S_NO_ERROR;
m_bStarted = true;
pProvider = m_pProvider; if(pProvider) pProvider->AddRef();
// Retrieve the sink to give to the provider
// =========================================
hres = m_pMainSink->GetMainProxy(&pEventSink); if(FAILED(hres)) return hres; }
CReleaseMe rm1(pProvider); CReleaseMe rm2(pEventSink);
if(pProvider) { //
// all calls to provider ( except AccessCheck ) should be made as
// the system. It is incorrect to propagate the client's identity
// along in this call.
//
IUnknown *pOldCtx, *pTmpCtx; hres = CoSwitchCallContext( NULL, &pOldCtx ); if ( FAILED( hres ) ) return hres; hres = pProvider->ProvideEvents(pEventSink, 0);
HRESULT hr = CoSwitchCallContext( pOldCtx, &pTmpCtx ); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Could not start provider %S. Error: %X\n", m_strName, hres)); CInUpdate iu( pNamespace ); UnloadProvider(); return WBEM_E_PROVIDER_FAILURE; } else if ( FAILED(hr) ) // propagate ProvideEvents code in success case.
{ hres = hr; }
return hres; } return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::AddActiveProviderEntryToRegistry() { LONG lRes; HKEY hkeyEss, hkeyNamespace, hkeyProvider;
DEBUGTRACE((LOG_ESS,"Adding provider %S from namespace %S to " " registry as active provider\n", m_strName, m_strNamespace));
//
// open ess key. It is expected that this key is already created.
//
lRes = RegOpenKeyExW( HKEY_LOCAL_MACHINE, WBEM_REG_ESS, 0, KEY_ALL_ACCESS, &hkeyEss );
if ( lRes == ERROR_SUCCESS ) { //
// open namespace key. It is expected that this key is already created.
//
lRes = RegOpenKeyExW( hkeyEss, m_strNamespace, 0, KEY_ALL_ACCESS, &hkeyNamespace );
if ( lRes == ERROR_SUCCESS ) { //
// create the provider sub key.
//
lRes = RegCreateKeyExW( hkeyNamespace, m_strName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyProvider, NULL );
if ( lRes == ERROR_SUCCESS ) { RegCloseKey( hkeyProvider ); } RegCloseKey( hkeyNamespace ); }
RegCloseKey( hkeyEss ); }
return HRESULT_FROM_WIN32( lRes ); }
HRESULT CEventProviderCache::CRecord::RemoveActiveProviderEntryFromRegistry() { LONG lRes; HKEY hkeyEss, hkeyNamespace;
DEBUGTRACE((LOG_ESS,"Removing provider %S from namespace %S from " " registry as active provider\n", m_strName, m_strNamespace));
//
// open ess key.
//
lRes = RegOpenKeyExW( HKEY_LOCAL_MACHINE, WBEM_REG_ESS, 0, KEY_ALL_ACCESS, &hkeyEss );
if ( lRes == ERROR_SUCCESS ) { //
// open namespace key. It is expected that this key is already created.
//
lRes = RegOpenKeyExW( hkeyEss, m_strNamespace, 0, KEY_ALL_ACCESS, &hkeyNamespace );
if ( lRes == ERROR_SUCCESS ) { //
// delete the provider sub key.
//
lRes = RegDeleteKeyW( hkeyNamespace, m_strName );
RegCloseKey( hkeyNamespace ); }
RegCloseKey( hkeyEss ); }
return HRESULT_FROM_WIN32( lRes ); } void CEventProviderCache::CRecord::UnloadProvider() { HRESULT hr;
DEBUGTRACE((LOG_ESS,"Unloading Provider %S in namespace %S\n", m_strName, m_strNamespace ));
//
// make sure the provider is removed from the provider cache. This is
// so if we load the provider again in the near future, we don't call
// ProvideEvents() on it twice.
//
if ( m_pProvider != NULL ) { CWbemPtr<_IWmiProviderCache> pProvCache;
hr = m_pProvider->QueryInterface( IID__IWmiProviderCache, (void**)&pProvCache );
if ( SUCCEEDED(hr) ) { hr = pProvCache->Expel( 0, GetCurrentEssContext() );
if ( FAILED(hr) ) { ERRORTRACE((LOG_ESS,"Could not expel provider %S from " "provider cache in namespace %S. HR=0x%x\n", m_strName,m_strNamespace,hr)); } }
m_pNamespace->PostponeRelease(m_pProvider); m_pProvider = NULL; }
if(m_pQuerySink) m_pNamespace->PostponeRelease(m_pQuerySink); m_pQuerySink = NULL;
if(m_pSecurity) m_pNamespace->PostponeRelease(m_pSecurity); m_pSecurity = NULL; m_bStarted = false;
//
// Report the MSFT_WmiEventProviderUnloaded event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiEventProviderUnloaded], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_strNamespace, m_strName); }
HRESULT CEventProviderCache::CRecord::Exec_NewQuery(CEssNamespace* pNamespace, CExecLine::CTurn* pTurn, DWORD dwID, LPCWSTR wszLanguage, LPCWSTR wszQuery, CAbstractEventSink* pDest) { HRESULT hres;
// Wait for our turn to make changes
// =================================
CExecLine::CInTurn it(&m_Line, pTurn); hres = ActualExecNewQuery(pNamespace, dwID, wszLanguage, wszQuery, pDest); if(FAILED(hres)) { //
// Check: it could be provider needs to be restarted
//
if(HRESULT_FACILITY(hres) != FACILITY_ITF) { ERRORTRACE((LOG_ESS, "Non-WMI error code recieved from provider " "%S: 0x%x. WMI will attempt to re-activate\n", m_strName, hres));
{ CInUpdate iu( pNamespace ); UnloadProvider(); } hres = ActualExecNewQuery(pNamespace, dwID, wszLanguage, wszQuery, pDest); } }
if(FAILED(hres)) { // Filter activation failed: deactivate
// =====================================
CInUpdate iu(pNamespace);
if(pNamespace->IsShutdown()) return WBEM_E_INVALID_NAMESPACE;
pNamespace->DeactivateFilter(pDest->GetEventFilter()); }
return hres; }
HRESULT CEventProviderCache::CRecord::ActualExecNewQuery( CEssNamespace* pNamespace, DWORD dwID, LPCWSTR wszLanguage, LPCWSTR wszQuery, CAbstractEventSink* pDest) { HRESULT hres;
// Ensure provider is loaded
// =========================
hres = Exec_LoadProvider(pNamespace); if(FAILED(hres)) return hres;
// With namespace locked, check if the provider is loaded
// ======================================================
IWbemEventProviderQuerySink* pSink = NULL; IWbemEventProviderSecurity* pSecurity = NULL; PSID pCopySid = NULL; { CInUpdate iu(pNamespace);
if(pNamespace->IsShutdown()) return WBEM_E_INVALID_NAMESPACE;
if(m_pQuerySink != NULL) { pSink = m_pQuerySink; pSink->AddRef(); } if(m_pSecurity != NULL) { pSecurity = m_pSecurity; pSecurity->AddRef();
// Make a copy of the filter's owner SID
// =====================================
PSID pActualSid = pDest->GetEventFilter()->GetOwner(); if(pActualSid != NULL) { pCopySid = new BYTE[GetLengthSid(pActualSid)]; if(pCopySid == NULL) return WBEM_E_OUT_OF_MEMORY; if(!CopySid(GetLengthSid(pActualSid), pCopySid, pActualSid)) { delete [] pCopySid; return WBEM_E_OUT_OF_MEMORY; } } } }
CReleaseMe rm1(pSink); CReleaseMe rm2(pSecurity); CVectorDeleteMe<BYTE> vdm((BYTE*)pCopySid); //
// Check security, if possible. If provider does not support the interface,
// interpret as "check SDs", as this may be a new-model-only provider
//
hres = WBEM_S_SUBJECT_TO_SDS; if(pSecurity) { DWORD dwSidLen = pCopySid ? GetLengthSid(pCopySid) : 0;
// Check security based on the SID or thread
// =========================================
if ( dwSidLen == 0 ) { //
// Check security based on the thread. First save the current
// call context, then switch it back after we're done.
//
IUnknown *pOldCtx, *pTmpCtx; hres = CoSwitchCallContext( NULL, &pOldCtx ); if ( FAILED( hres ) ) { return hres; } CWbemPtr<IUnknown> pNewCtx; hres = pDest->GetEventFilter()->SetThreadSecurity( &pNewCtx );
if ( FAILED( hres ) ) { return hres; } hres = pSecurity->AccessCheck( wszLanguage, wszQuery, 0, NULL );
HRESULT hr = CoSwitchCallContext( pOldCtx, &pTmpCtx );
if ( SUCCEEDED( hres ) && FAILED( hr ) ) { hres = hr; } } else { hres = pSecurity->AccessCheck( wszLanguage, wszQuery, dwSidLen, (BYTE*)pCopySid); }
//
// Report the MSFT_WmiEventProviderAccessCheck event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiEventProviderAccessCheck], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_strNamespace, m_strName, wszLanguage, wszQuery, pCopySid, dwSidLen, hres); } if(hres == WBEM_E_PROVIDER_NOT_CAPABLE) hres = WBEM_S_NO_ERROR;
if(SUCCEEDED(hres)) { // Security check has been passed: decrement remaining count
// =========================================================
pDest->GetEventFilter()->DecrementRemainingSecurityChecks(hres); } else { ERRORTRACE((LOG_ESS, "Event provider refused consumer registration " "query %S for security reasons: 0x%X\n", wszQuery, hres)); }
// Call "NewQuery" if required
// ===========================
if(SUCCEEDED(hres) && pSink) { IUnknown *pOldCtx, *pTmpCtx; hres = CoSwitchCallContext( NULL, &pOldCtx );
if ( SUCCEEDED(hres) ) { hres = pSink->NewQuery(dwID, (LPWSTR)wszLanguage,(LPWSTR)wszQuery); if(hres == WBEM_E_PROVIDER_NOT_CAPABLE) hres = WBEM_S_NO_ERROR;
HRESULT hr = CoSwitchCallContext( pOldCtx, &pTmpCtx ); if ( SUCCEEDED(hres) && FAILED(hr) ) hres = hr; }
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Event provider refused consumer registration " "query %S: error code 0x%X\n", wszQuery, hres)); }
//
// Report the MSFT_WmiEventProviderNewQuery event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiEventProviderNewQuery], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_strNamespace, m_strName, wszLanguage, wszQuery, dwID, hres); }
return hres; }
HRESULT CEventProviderCache::CRecord::Exec_CancelQuery( CEssNamespace* pNamespace, CExecLine::CTurn* pTurn, DWORD dwId) { CExecLine::CInTurn it(&m_Line, pTurn);
// With namespace locked, check if the provider is loaded
// ======================================================
IWbemEventProviderQuerySink* pSink = NULL; { CInUpdate iu(pNamespace);
if(pNamespace->IsShutdown()) return WBEM_E_INVALID_NAMESPACE;
if(m_pQuerySink == NULL) return WBEM_S_FALSE;
pSink = m_pQuerySink; pSink->AddRef(); }
CReleaseMe rm1(pSink); // Make the call
// =============
HRESULT hr;
IUnknown *pOldCtx, *pTmpCtx; hr = CoSwitchCallContext( NULL, &pOldCtx );
if ( SUCCEEDED(hr) ) { hr = pSink->CancelQuery(dwId); HRESULT hr2 = CoSwitchCallContext( pOldCtx, &pTmpCtx ); if ( SUCCEEDED(hr) && FAILED(hr2) ) hr = hr2; } //
// Report the MSFT_WmiEventProviderCancelQuery event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiEventProviderCancelQuery], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_strNamespace, m_strName, dwId, hr);
return hr; }
HRESULT CEventProviderCache::CRecord::DeliverProviderRequest( long lFlags) { HRESULT hres;
//
// The only requirement we support is WBEM_REQUIREMENT_RECHECK_SUBSCRIPTIONS
//
if(lFlags != WBEM_REQUIREMENTS_RECHECK_SUBSCRIPTIONS) return WBEM_E_INVALID_PARAMETER;
//
// With this object locked, retrieve all the filters for this provider.
// Get provider pointers, as well
//
CProviderSinkServer::TDestinationArray apDestinations; IWbemEventProviderQuerySink* pSink = NULL; IWbemEventProviderSecurity* pSecurity = NULL;
{ CInUpdate iu(m_pMainSink->GetNamespace());
hres = m_pMainSink->GetDestinations(apDestinations); if(FAILED(hres)) return hres;
if(m_pQuerySink != NULL) { pSink = m_pQuerySink; pSink->AddRef(); }
if(m_pSecurity != NULL) { pSecurity = m_pSecurity; pSecurity->AddRef(); } }
CReleaseMe rm1(pSink); CReleaseMe rm2(pSecurity);
//
// Iterate over them all, rechecking each with the provider
//
for(int i = 0; i < apDestinations.GetSize(); i++) { CProviderSinkServer::CEventDestination* pEventDest = apDestinations[i]; CAbstractEventSink* pDest = pEventDest->m_pSink;
//
// Retrieve the event filter associated with this sink
//
CEventFilter* pFilter = pDest->GetEventFilter(); if(pFilter == NULL) { ERRORTRACE((LOG_ESS, "Internal error: non-filter sink in proxy\n")); continue; }
//
// Retrieve the query from this filter.
//
LPWSTR wszQuery; LPWSTR wszQueryLanguage; BOOL bExact; hres = pFilter->GetCoveringQuery(wszQueryLanguage, wszQuery, bExact, NULL); if(FAILED(hres) || !bExact) continue; CVectorDeleteMe<WCHAR> vdm1(wszQuery); CVectorDeleteMe<WCHAR> vdm2(wszQueryLanguage);
//
// Check security first
//
if(pSecurity) { PSID pSid = pFilter->GetOwner(); if(pSid) { // Check security based on SID
hres = pSecurity->AccessCheck(wszQueryLanguage, wszQuery, GetLengthSid(pSid), (BYTE*)pSid); } else { //
// Check security based on the thread. First save the current
// call context, then switch it back after we're done.
//
IUnknown *pOldCtx, *pTmpCtx; hres = CoSwitchCallContext( NULL, &pOldCtx ); if ( FAILED( hres ) ) { return hres; } CWbemPtr<IUnknown> pNewCtx; hres = pFilter->SetThreadSecurity( &pNewCtx );
if ( FAILED(hres) ) { return hres; }
hres = pSecurity->AccessCheck( wszQueryLanguage, wszQuery, 0, NULL );
HRESULT hr = CoSwitchCallContext( pOldCtx, &pTmpCtx );
if ( SUCCEEDED( hres ) && FAILED( hr ) ) { hres = hr; } } if(FAILED(hres)) { //
// Increment remaining security checks, thus disabling filter
//
ERRORTRACE((LOG_ESS, "Disabling filter %S as provider denies " " access for this user: 0x%X\n", wszQuery, hres)); pFilter->IncrementRemainingSecurityChecks();
pDest->SetStatus( 0, WBEM_E_CALL_CANCELLED, NULL, NULL ); } }
if(SUCCEEDED(hres) && pSink) { //
// Check everything else --- do a NewQuery
//
hres = pSink->NewQuery(pEventDest->m_id, (LPWSTR)wszQueryLanguage, (LPWSTR)wszQuery); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Disabling filter %S as provider refuses " "registration: error code 0x%X\n", wszQuery, hres)); } } } return hres; }
CExecLine::CTurn* CEventProviderCache::CRecord::GetInLine() { return m_Line.GetInLine(); } void CEventProviderCache::CRecord::DiscardTurn(CExecLine::CTurn* pTurn) { m_Line.DiscardTurn(pTurn); }
HRESULT CEventProviderCache::CRecord::Activate(CEssNamespace* pNamespace, CRequest* pRequest, WBEM_REMOTE_TARGET_ID_TYPE idRequest) { CExecLine::CTurn* pTurn = GetInLine(); if(pTurn == NULL) return WBEM_E_OUT_OF_MEMORY;
m_lUsageCount++; m_LastUse = CWbemTime::GetCurrentTime();
if ( pRequest->GetDest()->GetEventFilter()->IsPermanent() ) { m_lPermUsageCount++; CheckPermanentUsage(); }
// Notify him of the new query, if required
// ========================================
HRESULT hr;
hr = PostponeNewQuery( pTurn, idRequest, L"WQL", pRequest->GetQuery(), pRequest->GetDest() ); if ( FAILED(hr) ) { DiscardTurn( pTurn ); return hr; }
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::Deactivate( CAbstractEventSink* pDest, WBEM_REMOTE_TARGET_ID_TYPE idRequest ) { if( !m_bProviderSet ) { // Provider is not registered.
// ===========================
return WBEM_S_FALSE; }
// Notify him of the cancellation, if required
// ===========================================
CExecLine::CTurn* pTurn = GetInLine();
if(pTurn == NULL) { return WBEM_E_OUT_OF_MEMORY; }
HRESULT hr = PostponeCancelQuery(pTurn, idRequest);
if ( FAILED(hr) ) { DiscardTurn( pTurn ); return hr; }
m_lUsageCount--; m_LastUse = CWbemTime::GetCurrentTime(); if ( pDest->GetEventFilter()->IsPermanent() ) { //
// TODO: Out usage counts can easily get out of wack because of
// mismatched Activate/Deactivates in the presence of failures.
// _DBG_ASSERT( m_lPermUsageCount > 0 );
//
m_lPermUsageCount--; CheckPermanentUsage(); } return WBEM_S_NO_ERROR; } HRESULT CEventProviderCache::CRecord::DeactivateFilter( CAbstractEventSink* pDest) { HRESULT hres;
// Try to remove it from our stub
// ==============================
WBEM_REMOTE_TARGET_ID_TYPE idRequest; hres = m_pMainSink->RemoveFilter(pDest, &idRequest);
if(hres == WBEM_E_NOT_FOUND) // not there --- no problem
return WBEM_S_FALSE; else if(FAILED(hres)) return hres;
hres = Deactivate( pDest, idRequest);
return hres; }
HRESULT CEventProviderCache::CRecord::ActivateIfNeeded(CRequest& Request, IN CEssNamespace* pNamespace) { HRESULT hres;
// Go through all the classes supplied by the provider and see if ours
// is an ancestor of any of them.
// ===================================================================
for(int j = 0; j < m_apQueries.GetSize(); j++) { CQueryRecord* pQueryRecord = m_apQueries[j];
_DBG_ASSERT( pQueryRecord != NULL ); pQueryRecord->EnsureClasses( pNamespace );
hres = pQueryRecord->DoesIntersectWithQuery(Request, pNamespace); pQueryRecord->ReleaseClasses();
if(FAILED(hres)) { // Something is wrong with the query itself --- no point in
// continuing to other registrations
// ========================================================
return hres; } else if(hres == WBEM_S_NO_ERROR) { DEBUGTRACE((LOG_ESS,"Activating filter '%S' with provider %S\n", Request.GetQuery(), m_strName ));
// First, increment the number of remaining security checks on this
// filter, since, even though we are adding it to the proxy, we do
// not want events reaching it until the provider said OK
// ================================================================
Request.GetDest()->GetEventFilter()-> IncrementRemainingSecurityChecks();
// Add this filter to the proxies
// ==============================
WBEM_REMOTE_TARGET_ID_TYPE idRequest; hres = m_pMainSink->AddFilter(Request.GetQuery(), Request.GetQueryExpr(), Request.GetDest(), &idRequest); if(FAILED(hres)) return hres;
// Schedule activation of this record, which will involve loading
// and notifying the provider. Also at that time, filter's security
// check count will be reduced and events can start flowing
// ================================================================
hres = Activate(pNamespace, &Request, idRequest);
if(hres != WBEM_S_NO_ERROR) // S_FALSE means no provider
{ m_pMainSink->RemoveFilter(Request.GetDest()); return hres; }
// No point in continuing --- the provider has been activated
// ==========================================================
break; } }
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::CRecord::CancelAllQueries() { HRESULT hres;
//
// With this object locked, retrieve all the filters for this provider.
// Get provider pointers, as well
//
CProviderSinkServer::TDestinationArray apDestinations; IWbemEventProviderQuerySink* pSink = NULL;
{ CInUpdate iu(m_pMainSink->GetNamespace());
if(m_pQuerySink == NULL) { //
// Nothing to cancel!
//
return WBEM_S_FALSE; }
hres = m_pMainSink->GetDestinations(apDestinations); if(FAILED(hres)) return hres;
pSink = m_pQuerySink; pSink->AddRef(); }
CReleaseMe rm1(pSink);
//
// Iterate over them all, rechecking each with the provider
//
for(int i = 0; i < apDestinations.GetSize(); i++) { CProviderSinkServer::CEventDestination* pEventDest = apDestinations[i];
//
// Notify the provider of the cancellation
//
CExecLine::CTurn* pTurn = GetInLine(); if( pTurn == NULL ) { return WBEM_E_OUT_OF_MEMORY; }
hres = PostponeCancelQuery(pTurn, pEventDest->m_id); if( FAILED(hres) ) { DiscardTurn( pTurn ); return hres; } }
return S_OK; }
//
// takes care of storing permanently the 'permanent' usage state of a provider
//
void CEventProviderCache::CRecord::CheckPermanentUsage() { HRESULT hr;
if ( IsSystem() ) { return; }
if ( m_lPermUsageCount == 0 && m_bRecorded ) { hr = RemoveActiveProviderEntryFromRegistry();
//
// no matter what the outcome, make sure to set recorded to false.
//
m_bRecorded = FALSE;
//
// since a namespace is deactivated before the filters are deactivated,
// ( because filter deactivation is postponed ), it is possible that
// the namespace key will be deleted by the time we get here.
// this happens when we're deactivating the last permanent consumer
// in the namespace.
//
if ( FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ) { ERRORTRACE((LOG_ESS,"Error removing active provider entry " "from registry in namespace %S. HR=0x%x\n", m_pNamespace->GetName(), hr )); } } else if ( m_lPermUsageCount > 0 && !m_bRecorded ) { hr = AddActiveProviderEntryToRegistry();
if ( SUCCEEDED(hr) ) { m_bRecorded = TRUE; } else { ERRORTRACE((LOG_ESS,"Error adding active provider entry " "to registry in namespace %S. HR=0x%x\n", m_pNamespace->GetName(), hr )); } } }
void CEventProviderCache::CRecord::ResetUsage() { DEBUGTRACE((LOG_ESS,"Resetting provider '%S' in namespace '%S' to prepare " "for resync.\n", m_strName, m_strNamespace )); //
// set a flag so that when all filters are reactivated we know to
// process them for this record.
//
m_bNeedsResync = TRUE;
CancelAllQueries(); m_lUsageCount = 0;
//
// when the changes to the event provider cache is committed, we will
// enumerate all records and remove ones having a perm usage count still 0
// from the registry.
//
m_lPermUsageCount = 0;
m_pMainSink->RemoveAllFilters(); }
bool CEventProviderCache::CRecord::DeactivateIfNotUsed() { if(m_lUsageCount == 0 && m_pProvider) { // Stop the provider
// =================
UnloadProvider(); DEBUGTRACE((LOG_ESS, "Unloading event provider %S\n", m_strName));
return true; } else return false; }
bool CEventProviderCache::CRecord::IsUnloadable() { return (IsActive() && GetUsageCount() == 0); }
DWORD CEventProviderCache::CRecord::GetProvidedEventMask( IWbemClassObject* pClass, BSTR strClassName) { DWORD dwEventMask = 0;
// Go through all its registered queries
// =====================================
for(int j = 0; j < m_apQueries.GetSize(); j++) { CRecord::CQueryRecord* pQueryRecord = m_apQueries.GetAt(j);
_DBG_ASSERT( pQueryRecord != NULL ); pQueryRecord->EnsureClasses( m_pNamespace );
dwEventMask |= pQueryRecord->GetProvidedEventMask(pClass, strClassName);
pQueryRecord->ReleaseClasses(); }
return dwEventMask; }
bool CEventProviderCache::CSystemRecord::DeactivateIfNotUsed() { //
// System providers cannot be deactivated
//
return false; } bool CEventProviderCache::CSystemRecord::IsUnloadable() { //
// System providers cannot be deactivated
//
return false; } /*
HRESULT CEventProviderCache::CSystemRecord::PostponeNewQuery( CExecLine::CTurn* pTurn, DWORD dwId, LPCWSTR wszQueryLanguage, LPCWSTR wszQuery, CAbstractEventSink* pDest) { //
// System providers do not need calls to them postponed!
//
return Exec_NewQuery(m_pNamespace, pTurn, dwId, wszQueryLanguage, wszQuery, pDest); }
HRESULT CEventProviderCache::CSystemRecord::PostponeCancelQuery( CExecLine::CTurn* pTurn, DWORD dwId) { //
// System providers do not need calls to them postponed!
//
return Exec_CancelQuery(m_pNamespace, pTurn, dwId); } */
//******************************************************************************
//******************************************************************************
//
// REQUEST
//
//******************************************************************************
//******************************************************************************
CEventProviderCache::CRequest::CRequest(IN CAbstractEventSink* pDest, LPWSTR wszQuery, QL_LEVEL_1_RPN_EXPRESSION* pExp) : m_pDest(pDest), m_wszQuery(wszQuery), m_pExpr(pExp), m_dwEventMask(0), m_papInstanceClasses(NULL), m_pEventClass(NULL) { }
CEventProviderCache::CRequest::~CRequest() { // Do not delete namespace, language, and query, and QL -- they were STOREd
// ========================================================================
if(m_papInstanceClasses) delete m_papInstanceClasses; if(m_pEventClass) m_pEventClass->Release(); }
INTERNAL QL_LEVEL_1_RPN_EXPRESSION* CEventProviderCache::CRequest:: GetQueryExpr() { return m_pExpr; }
DWORD CEventProviderCache::CRequest::GetEventMask() { if(m_dwEventMask == 0) { QL_LEVEL_1_RPN_EXPRESSION* pExpr = GetQueryExpr(); if(pExpr == NULL) return 0; m_dwEventMask = CEventRepresentation::GetTypeMaskFromName(pExpr->bsClassName); }
return m_dwEventMask; } HRESULT CEventProviderCache::CRequest::GetInstanceClasses( CEssNamespace* pNamespace, INTERNAL CClassInfoArray** ppClasses) { *ppClasses = NULL; if(!m_papInstanceClasses) { QL_LEVEL_1_RPN_EXPRESSION* pExpr = GetQueryExpr(); if(pExpr == NULL) return WBEM_E_OUT_OF_MEMORY;
HRESULT hres = CQueryAnalyser::GetPossibleInstanceClasses( pExpr, m_papInstanceClasses); if(FAILED(hres)) { return hres; }
if(m_papInstanceClasses == NULL) return WBEM_E_OUT_OF_MEMORY;
// Get the actual classes from the namespace
// =========================================
for(int i = 0; i < m_papInstanceClasses->GetNumClasses(); i++) { CClassInformation* pInfo = m_papInstanceClasses->GetClass(i); _IWmiObject* pClass = NULL;
hres = pNamespace->GetClass(pInfo->m_wszClassName, &pClass); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Could not get class %S for which intrinsic events" " are requested. Error code: %X\n", pInfo->m_wszClassName, hres));
delete m_papInstanceClasses; m_papInstanceClasses = NULL;
if(hres == WBEM_E_NOT_FOUND) hres = WBEM_E_INVALID_CLASS;
return hres; }
pInfo->m_pClass = pClass; }
} *ppClasses = m_papInstanceClasses; return WBEM_S_NO_ERROR; }
INTERNAL IWbemClassObject* CEventProviderCache::CRequest::GetEventClass( CEssNamespace* pNamespace) { HRESULT hres; if(m_pEventClass == NULL) { QL_LEVEL_1_RPN_EXPRESSION* pExpr = GetQueryExpr(); if(pExpr == NULL) return NULL;
_IWmiObject* pClass = NULL; hres = pNamespace->GetClass(pExpr->bsClassName, &pClass); if(FAILED(hres)) { return NULL; } m_pEventClass = pClass; }
return m_pEventClass; }
HRESULT CEventProviderCache::CRequest::CheckValidity(CEssNamespace* pNamespace) { if(GetQueryExpr() == NULL) return WBEM_E_INVALID_QUERY;
if(GetEventClass(pNamespace) == NULL) return WBEM_E_INVALID_CLASS;
return WBEM_S_NO_ERROR; } //******************************************************************************
//******************************************************************************
//
// PROVIDER CACHE
//
//******************************************************************************
//******************************************************************************
CEventProviderCache::CEventProviderCache(CEssNamespace* pNamespace) : m_pNamespace(pNamespace), m_pInstruction(NULL), m_bInResync(FALSE) { }
CEventProviderCache::~CEventProviderCache() { Shutdown(); }
// assumes: in m_cs
long CEventProviderCache::FindRecord(LPCWSTR wszName) { for(long l = 0; l < m_aRecords.GetSize(); l++) { if(!wbem_wcsicmp(wszName, m_aRecords[l]->m_strName)) { return l; } }
return -1; }
HRESULT CEventProviderCache::AddProvider(IWbemClassObject* pWin32Prov) { HRESULT hres;
_DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
// Determine provider's name
// =========================
BSTR strName; hres = CRecord::GetProviderInfo(pWin32Prov, strName); if(FAILED(hres)) return hres; CSysFreeMe sfm1(strName);
// Check if it exists
// ==================
long lIndex = FindRecord(strName); if(lIndex != -1) { // Already there
// =============
hres = m_aRecords[lIndex]->SetProvider(pWin32Prov); if(FAILED(hres)) return hres;
return WBEM_S_FALSE; }
// Create a new provider record
// ============================
CRecord* pNewRecord = _new CRecord; if(pNewRecord == NULL) return WBEM_E_OUT_OF_MEMORY; pNewRecord->AddRef(); CTemplateReleaseMe<CRecord> rm1(pNewRecord); hres = pNewRecord->Initialize( strName, m_pNamespace ); if(FAILED(hres)) return hres;
hres = pNewRecord->SetProvider(pWin32Prov); if(FAILED(hres)) return hres;
// Store it
// ========
if(m_aRecords.Add(pNewRecord) < 0) { delete pNewRecord; return WBEM_E_OUT_OF_MEMORY; }
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::AddSystemProvider(IWbemEventProvider* pProvider, LPCWSTR wszName, long lNumQueries, LPCWSTR* awszQueries) { HRESULT hres; _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
//
// First of all, construct a system provider record and add it
//
CSystemRecord* pNewRecord = new CSystemRecord; if(pNewRecord == NULL) return WBEM_E_OUT_OF_MEMORY; pNewRecord->AddRef(); CTemplateReleaseMe<CSystemRecord> rm1(pNewRecord); hres = pNewRecord->Initialize( wszName, m_pNamespace); if(FAILED(hres)) return hres;
//
// Now, add all the queries in
//
hres = pNewRecord->SetQueries(m_pNamespace, lNumQueries, awszQueries); if(FAILED(hres)) return hres;
//
// Populate it with the provider pointer
//
hres = pNewRecord->SetProviderPointer(m_pNamespace, pProvider); if(FAILED(hres)) return hres;
//
// Launch it
//
hres = pNewRecord->Exec_StartProvider(m_pNamespace); if(FAILED(hres)) return hres; if(m_aRecords.Add(pNewRecord) < 0) { return WBEM_E_OUT_OF_MEMORY; }
return WBEM_S_NO_ERROR; } HRESULT CEventProviderCache::RemoveProvider(IWbemClassObject* pWin32Prov) { HRESULT hres; _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
// Determine provider's name
// =========================
BSTR strName; hres = CRecord::GetProviderInfo(pWin32Prov, strName); if(FAILED(hres)) return hres;
// Find this record
// ================
long lIndex = FindRecord(strName); SysFreeString(strName); if(lIndex == -1) { return WBEM_S_FALSE; } else { m_aRecords[lIndex]->ResetUsage(); m_aRecords[lIndex]->ResetProvider();
if(m_aRecords[lIndex]->IsEmpty()) { m_aRecords.RemoveAt(lIndex); }
return WBEM_S_NO_ERROR; } }
HRESULT CEventProviderCache::CheckProviderRegistration( IWbemClassObject* pRegistration) { HRESULT hres; _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
// Create a new provider record
// ============================
CRecord* pRecord = new CRecord; if(pRecord == NULL) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<CRecord> dm1(pRecord); hres = pRecord->Initialize( NULL, m_pNamespace ); if(FAILED(hres)) return hres;
// Set the queries into it
// =======================
hres = pRecord->SetQueries(m_pNamespace, pRegistration); return hres; }
HRESULT CEventProviderCache::AddProviderRegistration( IWbemClassObject* pRegistration) { HRESULT hres; _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
BSTR strName;
hres = CRecord::GetRegistrationInfo( pRegistration, strName ); if( FAILED(hres) ) { return hres; }
CSysFreeMe sfm( strName );
long lIndex = FindRecord( strName ); if(lIndex == -1) { CRecord* pRecord = new CRecord; if(pRecord == NULL) return WBEM_E_OUT_OF_MEMORY; hres = pRecord->Initialize( strName, m_pNamespace );
if(FAILED(hres)) { delete pRecord; return hres; }
hres = pRecord->SetQueries(m_pNamespace, pRegistration);
if ( FAILED(hres) ) { delete pRecord; return hres; }
lIndex = m_aRecords.Add(pRecord);
if(lIndex == -1) { delete pRecord; return WBEM_E_OUT_OF_MEMORY; } } else { hres = m_aRecords[lIndex]->SetQueries(m_pNamespace, pRegistration); } return hres; }
HRESULT CEventProviderCache::RemoveProviderRegistration( IWbemClassObject* pRegistration) { HRESULT hres; _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
BSTR strName;
hres = CRecord::GetRegistrationInfo( pRegistration, strName ); if( FAILED(hres) ) { return hres; }
CSysFreeMe sfm( strName );
long lIndex = FindRecord( strName ); if(lIndex == -1) return WBEM_S_FALSE;
// Set registration info
// =====================
m_aRecords[lIndex]->ResetUsage(); m_aRecords[lIndex]->ResetQueries();
if(m_aRecords[lIndex]->IsEmpty()) { m_aRecords.RemoveAt(lIndex); }
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::ReleaseProvidersForQuery(CAbstractEventSink* pDest) { HRESULT hres;
//
// it is possible that this one function can be called without ns set
//
if ( m_pNamespace != NULL ) { _DBG_ASSERT( m_pNamespace->IsShutdown() || m_pNamespace->DoesThreadOwnNamespaceLock() ); }
// Search all the providers
// ========================
for(int i = 0; i < m_aRecords.GetSize(); i++) { CRecord* pRecord = m_aRecords[i]; hres = pRecord->DeactivateFilter(pDest);
// If failures occur, they are logged. Continue.
}
// Make sure unload instruction is running
// =======================================
EnsureUnloadInstruction();
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::LoadProvidersForQuery(LPWSTR wszQuery, QL_LEVEL_1_RPN_EXPRESSION* pExp, CAbstractEventSink* pDest) { HRESULT hres; _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
// DEBUGTRACE((LOG_ESS, "Activating providers for %S (%p)\n",
// wszQuery, pDest));
// Create a request record
// =======================
CRequest Request(pDest, wszQuery, pExp);
// Check query validity
// ====================
hres = Request.CheckValidity(m_pNamespace); if(FAILED(hres)) return hres;
// Search all the providers
// ========================
HRESULT hresGlobal = WBEM_S_NO_ERROR; for(int i = 0; i < m_aRecords.GetSize(); i++) { CRecord* pRecord = m_aRecords[i];
if ( !m_bInResync || pRecord->NeedsResync() ) { HRESULT hr = pRecord->ActivateIfNeeded(Request, m_pNamespace); if(FAILED(hr)) hresGlobal = hr; } }
return hresGlobal; }
void CEventProviderCache::EnsureUnloadInstruction() { if(m_pInstruction == NULL && m_pNamespace != NULL) { m_pInstruction = new CEventProviderWatchInstruction(this); if(m_pInstruction != NULL) { m_pInstruction->AddRef(); m_pNamespace->GetTimerGenerator().Set(m_pInstruction); } } }
DWORD CEventProviderCache::GetProvidedEventMask(IWbemClassObject* pClass) { HRESULT hres; _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
VARIANT v; VariantInit(&v); hres = pClass->Get(L"__CLASS", 0, &v, NULL, NULL); if(FAILED(hres)) return hres; CClearMe cm1(&v);
DWORD dwProvidedMask = 0;
// Search all the providers
// ========================
for(int i = 0; i < m_aRecords.GetSize(); i++) { CRecord* pRecord = m_aRecords[i]; dwProvidedMask |= pRecord->GetProvidedEventMask(pClass, V_BSTR(&v)); } return dwProvidedMask; } HRESULT CEventProviderCache::VirtuallyReleaseProviders() { _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
//
// just need to record the fact that we are in resync. This allows us to
// handle reactivation of filters differently than when not in resync.
// For example, during resync we only process reactivations for provider
// records that had changed causing the resync in the first place.
//
m_bInResync = TRUE;
return WBEM_S_NO_ERROR; } HRESULT CEventProviderCache::CommitProviderUsage() { _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( m_pNamespace->DoesThreadOwnNamespaceLock() );
// Called after VirtuallyReleaseProviders and re-activating all filters
// to actually deactivate all the providers whose usage count went to 0.
// =====================================================================
//
// need to process all records and ensure that any having a perm usage
// count of 0 be removed from the registry. Also make sure that we
// reset each records resync flag.
//
for( int i=0; i < m_aRecords.GetSize(); i++ ) { m_aRecords[i]->ResetNeedsResync(); m_aRecords[i]->CheckPermanentUsage(); }
// At this point, there is nothing to be done. When unload instruction
// executes, providers that are no longer needed will be unloaded. All we
// need to do is allow the unload instruction to proceed.
// ======================================================================
m_bInResync = FALSE; EnsureUnloadInstruction();
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::UnloadUnusedProviders(CWbemInterval Interval) { _DBG_ASSERT( m_pNamespace != NULL ); _DBG_ASSERT( !m_pNamespace->DoesThreadOwnNamespaceLock() );
{ CInUpdate iu(m_pNamespace); if( m_pNamespace->IsShutdown()) return WBEM_S_FALSE; if(m_bInResync) { // Usage counters are not up-to-date --- wait for the next time
// ============================================================
return WBEM_S_FALSE; } BOOL bDeactivated = FALSE; BOOL bActiveLeft = FALSE; for(int i = 0; i < m_aRecords.GetSize(); i++) { CRecord* pRecord = m_aRecords[i]; if(pRecord->IsActive() && CWbemTime::GetCurrentTime() - pRecord->m_LastUse > Interval) { if(pRecord->DeactivateIfNotUsed()) bDeactivated = TRUE; } //
// Check if we need to come back for this one
//
if(pRecord->IsUnloadable()) bActiveLeft = TRUE; } if(bDeactivated) m_pNamespace->GetTimerGenerator().ScheduleFreeUnusedLibraries(); if(!bActiveLeft && m_pInstruction) { m_pInstruction->Terminate(); m_pInstruction->Release(); m_pInstruction = NULL; } }
m_pNamespace->FirePostponedOperations();
return WBEM_S_NO_ERROR; }
HRESULT CEventProviderCache::Shutdown() { //
// check if we've already been shutdown. we don't need a cs here because
// this method is not multithread safe anyhow and is the only method that
// modifies the namespace member.
//
if ( m_pNamespace == NULL ) return WBEM_S_FALSE;
//
// namespace lock cannot be held when calling this method. This is
// because we will block here waiting for the timer instruction to
// shutdown and this thread aquires the namespace lock.
//
_DBG_ASSERT( !m_pNamespace->DoesThreadOwnNamespaceLock() );
if(m_pInstruction) { m_pInstruction->Terminate(); m_pInstruction->Release(); m_pInstruction = NULL; }
m_aRecords.RemoveAll();
//
// we don't need a cs here to modify the namespace because we are
// assured that the only other thread that can access us concurrently,
// (the timer thread) has been shutdown.
//
m_pNamespace = NULL;
return WBEM_S_NO_ERROR; }
void CEventProviderCache::DumpStatistics(FILE* f, long lFlags) { long lLoaded = 0; long lQueries = 0; long lProxies = 0; long lFilters = 0; long lDestinations = 0; long lTargetLists = 0; long lTargets = 0; long lPostponed = 0; for(int i = 0; i < m_aRecords.GetSize(); i++) { CRecord* pRecord = m_aRecords[i]; if(pRecord->m_pProvider) lLoaded++; lQueries += pRecord->m_apQueries.GetSize();
long lThisProxies = 0; long lThisFilters = 0; long lThisTargetLists = 0; long lThisTargets = 0; long lThisPostponed = 0; long lThisDestinations = 0; pRecord->m_pMainSink->GetStatistics(&lThisProxies, &lThisDestinations, &lThisFilters, &lThisTargetLists, &lThisTargets, &lThisPostponed);
lProxies += lThisProxies; lDestinations += lThisDestinations; lFilters += lThisFilters; lTargetLists += lThisTargetLists; lTargets += lThisTargets; lPostponed += lThisPostponed; }
fprintf(f, "%d provider records, %d definition queries, %d proxies\n" "%d destinations, %d proxy filters, %d proxy target lists\n" "%d proxy targets, %d postponed in proxies\n", m_aRecords.GetSize(), lQueries, lProxies, lDestinations, lFilters, lTargetLists, lTargets, lPostponed); }
CPostponedNewQuery::CPostponedNewQuery(CEventProviderCache::CRecord* pRecord, DWORD dwId, LPCWSTR wszQueryLanguage, LPCWSTR wszQuery, CExecLine::CTurn* pTurn, CAbstractEventSink* pDest) : m_pRecord(pRecord), m_dwId(dwId), m_pTurn(pTurn), m_pcsQuery(NULL), m_pDest(pDest) { m_pRecord->AddRef(); m_pDest->AddRef();
// Figure out how much space we need
// =================================
int nSpace = CCompressedString::ComputeNecessarySpace(wszQuery);
// Allocate this string on the temporary heap
// ==========================================
m_pcsQuery = (CCompressedString*)CTemporaryHeap::Alloc(nSpace); if(m_pcsQuery == NULL) return;
m_pcsQuery->SetFromUnicode(wszQuery); }
CPostponedNewQuery::~CPostponedNewQuery() { if(m_pTurn) m_pRecord->DiscardTurn(m_pTurn); if(m_pcsQuery) CTemporaryHeap::Free(m_pcsQuery, m_pcsQuery->GetLength()); if(m_pDest) m_pDest->Release();
m_pRecord->Release(); } HRESULT CPostponedNewQuery::Execute(CEssNamespace* pNamespace) { if(m_pcsQuery == NULL) return WBEM_E_OUT_OF_MEMORY;
HRESULT hres = m_pRecord->Exec_NewQuery(pNamespace, m_pTurn, m_dwId, L"WQL", m_pcsQuery->CreateWStringCopy(), m_pDest); m_pTurn = NULL; return hres; }
void* CPostponedNewQuery::operator new(size_t nSize) { return CTemporaryHeap::Alloc(nSize); } void CPostponedNewQuery::operator delete(void* p) { CTemporaryHeap::Free(p, sizeof(CPostponedNewQuery)); }
|