|
|
//******************************************************************************
//
// FILTPROX.CPP
//
// Copyright (C) 1996-1999 Microsoft Corporation
//
//******************************************************************************
#include "precomp.h"
#include <stdio.h>
#include "pragmas.h"
#include <wbemcomn.h>
#include "filtprox.h"
#include <eventrep.h>
#include <evtools.h>
#include <wbemdcpl.h>
#include <newnew.h>
#include <winntsec.h>
#ifdef DBG
#define _ESSCLI_ASSERT(X) { if (!(X)) { DebugBreak(); } }
#else
#define _ESSCLI_ASSERT(X)
#endif
CTempMemoryManager g_TargetsManager;
bool TempSetTargets(WBEM_REM_TARGETS* pTargets, CSortedArray* pTrues) { int nSize = pTrues->Size(); pTargets->m_lNumTargets = nSize; pTargets->m_aTargets = (WBEM_REMOTE_TARGET_ID_TYPE*) g_TargetsManager.Allocate( sizeof(WBEM_REMOTE_TARGET_ID_TYPE) * nSize); if(pTargets->m_aTargets == NULL) return false;
for(int i = 0; i < nSize; i++) { pTargets->m_aTargets[i] = (WBEM_REMOTE_TARGET_ID_TYPE)pTrues->GetAt(i); }
return true; }
void TempClearTargets(WBEM_REM_TARGETS* pTargets) { g_TargetsManager.Free(pTargets->m_aTargets, sizeof(WBEM_REMOTE_TARGET_ID_TYPE) * pTargets->m_lNumTargets); }
//******************************************************************************
//******************************************************************************
// META DATA
//******************************************************************************
//******************************************************************************
HRESULT CWrappingMetaData::GetClass(LPCWSTR wszName, IWbemContext* pContext, _IWmiObject** ppClass) { HRESULT hres; IWbemClassObject* pObj; *ppClass = NULL; hres = m_pDest->GetClass(wszName, pContext, &pObj); if ( FAILED(hres) ) { return hres; }
CReleaseMe rm1(pObj); return pObj->QueryInterface(IID__IWmiObject, (void**)ppClass); }
//******************************************************************************
//******************************************************************************
// FILTER PROXY MANAGER
//******************************************************************************
//******************************************************************************
CFilterProxyManager::CFilterProxyManager(CLifeControl* pControl) : CFilterProxyManagerBase( pControl ), m_lRef(0), m_pStub(NULL), m_pMetaData(NULL), m_pMultiTarget(NULL), m_pSpecialContext(NULL), m_XProxy(this), m_lExtRef(0), m_hthreadSend(NULL), m_heventDone(NULL), m_heventBufferNotFull(NULL), m_heventBufferFull(NULL), m_heventEventsPending(NULL), m_dwLastSentStamp(0), m_pMultiTargetStream( NULL ) { }
CFilterProxyManager::~CFilterProxyManager() { StopSendThread();
if(m_pMetaData) m_pMetaData->Release(); if(m_pStub) m_pStub->Release(); if(m_pMultiTarget) m_pMultiTarget->Release(); }
ULONG STDMETHODCALLTYPE CFilterProxyManager::AddRef() { // This is an AddRef from a client. Increment a special counter as well
// ====================================================================
InterlockedIncrement(&m_lExtRef);
return InterlockedIncrement(&m_lRef); }
ULONG STDMETHODCALLTYPE CFilterProxyManager::Release() { // This is a Release from a client. Check if the client has released all
// references to the proxy, in which case we need to disconnect ourselves
// ======================================================================
if(InterlockedDecrement(&m_lExtRef) == 0) { EnterCriticalSection(&m_cs); IWbemFilterStub* pStub = m_pStub; InterlockedIncrement(&m_lRef); LeaveCriticalSection(&m_cs); if(pStub) pStub->UnregisterProxy(&m_XProxy);
InterlockedDecrement(&m_lRef); }
long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) delete this; return lRef; }
ULONG STDMETHODCALLTYPE CFilterProxyManager::AddRefProxy() { // AddRef from proxy.
return InterlockedIncrement(&m_lRef); }
ULONG STDMETHODCALLTYPE CFilterProxyManager::ReleaseProxy() { // Release from proxy.
long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) delete this; return lRef; }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown) *ppv = (IUnknown*)this; else if(riid == IID_IMarshal) *ppv = (IMarshal*)this; else if(riid == IID_IWbemFilterProxy || riid == IID_IWbemLocalFilterProxy) *ppv = (IWbemLocalFilterProxy*)&m_XProxy; else return E_NOINTERFACE;
((IUnknown*)*ppv)->AddRef(); return S_OK; } HRESULT STDMETHODCALLTYPE CFilterProxyManager::Initialize(IWbemMetaData* pMetaData, IWbemMultiTarget* pMultiTarget) { CInCritSec ics(&m_cs);
if(m_pMetaData) m_pMetaData->Release(); m_pMetaData = new CWrappingMetaData(pMetaData); if(m_pMetaData) m_pMetaData->AddRef(); else return WBEM_E_OUT_OF_MEMORY;
if(m_pMultiTarget) m_pMultiTarget->Release(); m_pMultiTarget = pMultiTarget; if(m_pMultiTarget) m_pMultiTarget->AddRef();
if(GetMainProxy() == NULL) return WBEM_E_OUT_OF_MEMORY;
return S_OK; }
HRESULT CFilterProxyManager::SetStub(IWbemFilterStub* pStub) { if(m_pStub) m_pStub->Release(); m_pStub = pStub; if(m_pStub) m_pStub->AddRef();
// Initialize ourselves
// ====================
HRESULT hres = m_pStub->RegisterProxy(&m_XProxy);
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Failed to register proxy with stub: %X\n", hres)); return hres; }
return S_OK; }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::Lock() { if(m_Lock.Enter()) // old implementation: == WAIT_OBJECT_0)
{ return S_OK; } else return WBEM_E_CRITICAL_ERROR; }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::Unlock() { m_Lock.Leave(); return S_OK; }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::AddFilter(IWbemContext* pContext, LPCWSTR wszQuery, WBEM_REMOTE_TARGET_ID_TYPE idFilter) { // Parse the query
// ===============
CTextLexSource Source((LPWSTR)wszQuery); QL1_Parser Parser(&Source); QL_LEVEL_1_RPN_EXPRESSION* pExp; if(Parser.Parse(&pExp) != QL1_Parser::SUCCESS) { ERRORTRACE((LOG_ESS, "Filter proxy unable to parse %S\n", wszQuery)); return WBEM_E_UNPARSABLE_QUERY; }
CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm(pExp); return AddFilter(pContext, wszQuery, pExp, idFilter); } HRESULT CFilterProxyManager::AddFilter(IWbemContext* pContext, LPCWSTR wszQuery, QL_LEVEL_1_RPN_EXPRESSION* pExp, WBEM_REMOTE_TARGET_ID_TYPE idFilter) { CInCritSec ics(&m_cs);
//
// Record the filter in our array
//
m_mapQueries[idFilter] = wszQuery;
//
// Add the filter to all our subproxies
//
HRESULT hresGlobal = S_OK; for(int i = 0; i < m_apProxies.GetSize(); i++) { HRESULT hres; if(m_apProxies[i] == NULL) continue; hres = m_apProxies[i]->AddFilter(GetProperContext(pContext), wszQuery, pExp, idFilter); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to add filter %S to sub-proxy in " "process %d.\n", wszQuery, GetCurrentProcessId())); hresGlobal = hres; } } return hresGlobal; }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::RemoveFilter( IWbemContext* pContext, WBEM_REMOTE_TARGET_ID_TYPE idFilter) { CInCritSec ics(&m_cs);
//
// Remove the filter from our array
//
m_mapQueries.erase(idFilter);
//
// Remove the filter from all our subproxies
//
HRESULT hresGlobal = S_OK; for(int i = 0; i < m_apProxies.GetSize(); i++) { HRESULT hres; if(m_apProxies[i] == NULL) continue; hres = m_apProxies[i]->RemoveFilter(GetProperContext(pContext), idFilter); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to remove filter from sub-proxy in " "process %d.\n", GetCurrentProcessId())); hresGlobal = hres; } } return hresGlobal; }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::RemoveAllFilters(IWbemContext* pContext) { CInCritSec ics(&m_cs);
//
// Clear our filter array
//
m_mapQueries.clear();
//
// Remove all filters from all our subproxies
//
HRESULT hresGlobal = S_OK; for(int i = 0; i < m_apProxies.GetSize(); i++) { HRESULT hres; if(m_apProxies[i] == NULL) continue; hres = m_apProxies[i]->RemoveAllFilters(GetProperContext(pContext)); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to remove all filters from sub-proxy " "in process %d.\n", GetCurrentProcessId())); hresGlobal = hres; } } return hresGlobal; } HRESULT STDMETHODCALLTYPE CFilterProxyManager::AllowUtilizeGuarantee() { CInCritSec ics(&m_cs);
//
// Definition queries should be sent to the main (first) proxy only
//
if(m_apProxies.GetSize() == 0) return WBEM_E_UNEXPECTED;
if(m_apProxies[0] == NULL) return WBEM_S_FALSE;
return m_apProxies[0]->AllowUtilizeGuarantee(); } HRESULT STDMETHODCALLTYPE CFilterProxyManager::AddDefinitionQuery( IWbemContext* pContext, LPCWSTR wszQuery) { CInCritSec ics(&m_cs);
//
// Definition queries should be sent to the main (first) proxy only
//
if(m_apProxies.GetSize() == 0) return WBEM_E_UNEXPECTED; if(m_apProxies[0] == NULL) return WBEM_S_FALSE; return m_apProxies[0]->AddDefinitionQuery(GetProperContext(pContext), wszQuery); }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::RemoveAllDefinitionQueries( IWbemContext* pContext) { //
// Definition queries should be sent to the main (first) proxy only
//
if(m_apProxies.GetSize() == 0) return WBEM_E_UNEXPECTED; if(m_apProxies[0] == NULL) return WBEM_S_FALSE;
return m_apProxies[0]->RemoveAllDefinitionQueries( GetProperContext(pContext)); }
HRESULT STDMETHODCALLTYPE CFilterProxyManager::Disconnect() { // We must make sure that once Disconnect returns, no events will be
// delivered
// =================================================================
CInLock<CFilterProxyManager> il(this); { CInCritSec ics(&m_cs); if(m_pMetaData) m_pMetaData->Release(); m_pMetaData = NULL; if(m_pStub) m_pStub->Release(); m_pStub = NULL; if(m_pMultiTarget) m_pMultiTarget->Release(); m_pMultiTarget = NULL; }
return WBEM_S_NO_ERROR; }
IWbemContext* CFilterProxyManager::GetProperContext(IWbemContext* pCurrentContext) { // If we are a real, out-of-proc, proxy, we should not use this context,
// because the thread that owns it is currently stuck in an RPC call to us
// and will not be able to process dependent requests. Instead, we must
// use the "special" context that will cause the thread pool to always
// create a new thread if needed
// =======================================================================
if(m_pSpecialContext) return m_pSpecialContext; else return pCurrentContext; }
HRESULT CFilterProxyManager::SetStatus(long lFlags, HRESULT hResult, BSTR strResult, IWbemClassObject* pErrorObj) { HRESULT hres;
CWbemPtr<IWbemMultiTarget> pMultiTarget;
{ CInLock<CFilterProxyManager> il(this);
if(m_pMultiTarget == NULL) return WBEM_E_UNEXPECTED;
pMultiTarget = m_pMultiTarget; }
//
// There is only one reason we support this call: to re-check all
// subscriptions for validity/security
//
if(lFlags != WBEM_STATUS_REQUIREMENTS || hResult != WBEM_REQUIREMENTS_RECHECK_SUBSCRIPTIONS) { return WBEM_E_INVALID_PARAMETER; }
//
// Retrieve "special" interface we use for this purpose
//
IWbemEventProviderRequirements* pReq = NULL; hres = pMultiTarget->QueryInterface(IID_IWbemEventProviderRequirements, (void**)&pReq); if(FAILED(hres)) return hres; CReleaseMe rm1(pReq); return pReq->DeliverProviderRequest(hResult); }
STDMETHODIMP CFilterProxyManager::GetRestrictedSink( long lNumQueries, const LPCWSTR* awszQueries, IUnknown* pCallback, IWbemEventSink** ppSink) { // Basic parameter validation
if(lNumQueries < 1) return WBEM_E_INVALID_PARAMETER; if(ppSink == NULL) return WBEM_E_INVALID_PARAMETER;
*ppSink = NULL; HRESULT hres; //
// Construct a new filter proxy
//
CFilterProxy* pNewProxy = new CFilterProxy(this, pCallback); if(pNewProxy == NULL) return WBEM_E_OUT_OF_MEMORY;
//
// Add all the definition queries
//
for(long i = 0; i < lNumQueries; i++) { LPCWSTR wszQuery = awszQueries[i]; if(wszQuery == NULL) { delete pNewProxy; return WBEM_E_INVALID_PARAMETER; }
hres = pNewProxy->AddDefinitionQuery(NULL, wszQuery); if(FAILED(hres)) { delete pNewProxy; return hres; } }
//
// if we made it here, then all definition queries were correctly added
// and we can now utilize these definitions for optimizing the filter.
//
pNewProxy->AllowUtilizeGuarantee();
{ CInCritSec ics(&m_cs); for(TIterator it = m_mapQueries.begin(); it != m_mapQueries.end(); it++) { // Parse the query
// ===============
LPCWSTR wszQuery = it->second; WBEM_REMOTE_TARGET_ID_TYPE idFilter = it->first;
CTextLexSource Source(wszQuery); QL1_Parser Parser(&Source); QL_LEVEL_1_RPN_EXPRESSION* pExp; if(Parser.Parse(&pExp) != QL1_Parser::SUCCESS) { ERRORTRACE((LOG_ESS, "Filter proxy unable to parse %S\n", wszQuery)); continue; } CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm(pExp); pNewProxy->AddFilter(NULL, wszQuery, pExp, idFilter); }
if(m_apProxies.Add(pNewProxy) < 0) { delete pNewProxy; return WBEM_E_OUT_OF_MEMORY; }
pNewProxy->SetRunning(); } return pNewProxy->QueryInterface(IID_IWbemEventSink, (void**)ppSink); }
STDMETHODIMP CFilterProxyManager::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext, void* pvReserved, DWORD mshlFlags, CLSID* pClsid) { *pClsid = CLSID_WbemFilterProxy; return WBEM_S_NO_ERROR; }
STDMETHODIMP CFilterProxyManager::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext, void* pvReserved, DWORD mshlFlags, ULONG* plSize) { return CoGetMarshalSizeMax(plSize, IID_IWbemFilterStub, m_pStub, dwDestContext, pvReserved, mshlFlags); }
STDMETHODIMP CFilterProxyManager::MarshalInterface(IStream* pStream, REFIID riid, void* pv, DWORD dwDestContext, void* pvReserved, DWORD mshlFlags) { return CoMarshalInterface(pStream, IID_IWbemFilterStub, m_pStub, dwDestContext, pvReserved, mshlFlags); }
STDMETHODIMP CFilterProxyManager::UnmarshalInterface(IStream* pStream, REFIID riid, void** ppv) { //
// before unmarshaling, we must first check we are unmarshaling due to
// a call from wmi ( or local system rather ). Because we're going to
// be calling back 'blindly' to the passed in reference, we need to
// ensure we're not going to 'give away the farm'. Remember that this
// custom marshaler can be used in any DCOM server, so we must ensure
// that it can't be misused to get an arbitrary process to call you back
// at potentially impersonate level.
//
CWbemPtr<IServerSecurity> pSec; HRESULT hr = CoGetCallContext( IID_IServerSecurity, (void**)&pSec ); if ( SUCCEEDED(hr) ) { CNtSid ProcessSid( CNtSid::CURRENT_USER ); if ( ProcessSid.GetStatus() != CNtSid::NoError ) return WBEM_E_ACCESS_DENIED; hr = pSec->ImpersonateClient(); if ( FAILED(hr) ) return hr;
CNtSid CallerSid( CNtSid::CURRENT_THREAD ); pSec->RevertToSelf();
if ( CallerSid.GetStatus() != CNtSid::NoError ) return WBEM_E_ACCESS_DENIED; PSID pLocalSystemSid;
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY; if ( AllocateAndInitializeSid( &id, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &pLocalSystemSid ) ) { BOOL bOk = EqualSid( CallerSid.GetPtr(), pLocalSystemSid ) || EqualSid( CallerSid.GetPtr(), ProcessSid.GetPtr() ); FreeSid( pLocalSystemSid );
if ( !bOk ) return WBEM_E_ACCESS_DENIED; } else { return WBEM_E_OUT_OF_MEMORY; } }
// Unmarshal the stub pointer
// ==========================
HRESULT hres = CoUnmarshalInterface(pStream, IID_IWbemFilterStub, (void**)&m_pStub); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to unmarshal filter stub: %X\n", hres)); return hres; }
// Since we are unmarshalling, this must be a real proxy. Real proxies
// should use a "special" context when calling back into CIMOM to make sure
// that they do not cause a deadlock, because a thread in CIMOM is stuck in
// an RPC call to this proxy and is not processing dependent requests.
// ========================================================================
IWbemCausalityAccess* pCausality = NULL; hres = CoCreateInstance(CLSID_WbemContext, NULL, CLSCTX_INPROC_SERVER, IID_IWbemCausalityAccess, (void**)&pCausality); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to create a context object in proxy: " "error code 0x%X\n", hres)); return hres; } CReleaseMe rm1(pCausality);
hres = pCausality->MakeSpecial(); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to construct special context object in " "proxy: error code 0x%X\n", hres)); return hres; } hres = pCausality->QueryInterface(IID_IWbemContext, (void**)&m_pSpecialContext); if(FAILED(hres)) { // Out of memory?
// ==============
return hres; } // Initialize ourselves
// ====================
hres = m_pStub->RegisterProxy(&m_XProxy);
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Failed to register proxy with stub: %X\n", hres)); return hres; }
//
// What we must return is our main proxy
//
if(GetMainProxy()) return GetMainProxy()->QueryInterface(riid, ppv); else return WBEM_E_CRITICAL_ERROR; }
INTERNAL IWbemEventSink* CFilterProxyManager::GetMainProxy() { //
// We are being asked for the sink to give to the provider. It is possible
// that we do not have a sink --- that will be the case if the provider
// has unloaded. In that case, we must be sure to create it!
//
if(m_apProxies.GetSize() == 0) { CFilterProxy* pMainProxy = new CFilterProxy(this); if(pMainProxy == NULL) return NULL; pMainProxy->SetRunning();
if(m_apProxies.Add(pMainProxy) < 0) { delete pMainProxy; return NULL; } return pMainProxy; } else { if(m_apProxies[0] == NULL) { CFilterProxy* pMainProxy = new CFilterProxy(this); if(pMainProxy == NULL) return NULL; pMainProxy->SetRunning();
m_apProxies.SetAt(0, pMainProxy); } return m_apProxies[0]; } }
HRESULT CFilterProxyManager::GetMetaData(RELEASE_ME CWrappingMetaData** ppMeta) { *ppMeta = m_pMetaData; (*ppMeta)->AddRef(); return S_OK; }
HRESULT CFilterProxyManager::RemoveProxy(CFilterProxy* pProxy) { //
// Called when a proxy is fully released by the client, and calls on the
// manager to self-destruct
//
CFilterProxy* pOldProxy = NULL;
{ CInCritSec ics(&m_cs); for(int i = 0; i < m_apProxies.GetSize(); i++) { if(m_apProxies[i] == pProxy) { RemoveProxyLatency(pProxy); m_apProxies.RemoveAt(i, &pOldProxy); break; } } } if(pOldProxy) { // We don't do a release because pProxy's refcount is already 0 (which
// is why we're in this function). Normally RemoveAt would have
// deleted it, but since we passed in &pOldProxy, it didn't. We do this
// so pOldProxy doesn't do its final release of the manager which could
// destruct the manager while we're holding onto the manager's lock.
delete pOldProxy;
return WBEM_S_NO_ERROR; } else return WBEM_E_NOT_FOUND; }
STDMETHODIMP CFilterProxyManager::ReleaseMarshalData(IStream* pStream) { return CoReleaseMarshalData(pStream); }
STDMETHODIMP CFilterProxyManager::DisconnectObject(DWORD dwReserved) { // BUGBUG
return WBEM_E_UNEXPECTED; }
HRESULT CFilterProxyManager::DeliverEvent(long lNumToSend, IWbemClassObject** apEvents, WBEM_REM_TARGETS* aTargets, long lSDLength, BYTE* pSD) { //
// we need to hold the proxy lock when signalling an event.
// the reason for this is that when a call to disconnect() returns,
// we can be absolutely sure that no events will be delivered to the
// stub. Without locking here, just after the check for multitarget,
// disconnect could be called setting multitarget to null and then
// returning, however, just after the DeliverEvent call is made.
//
CInLock<CFilterProxyManager> il(this);
if(m_pMultiTarget) return m_pMultiTarget->DeliverEvent(lNumToSend, apEvents, aTargets, lSDLength, pSD); else return CO_E_OBJNOTCONNECTED; }
HRESULT CFilterProxyManager::DeliverEventMT(long lNumToSend, IWbemClassObject** apEvents, WBEM_REM_TARGETS* aTargets, long lSDLength, BYTE* pSD, IWbemMultiTarget * pMultiTarget) { //
// we need to hold the proxy lock when signalling an event. There are
// two reasons for this. The first is that during resync of ess, it
// must ensure that no events are delivered, else they would be lost.
// the way ess ensures this is by grabbing the locks of all the proxies.
// The other reason is so that when a call to disconnect() returns,
// we can be absolutely sure that no events will be delivered to the
// stub. Without locking here, just after the check for multitarget,
// disconnect could be called setting multitarget to null and then
// returning, however, just after the DeliverEvent call is made.
//
// This assertion is for this func to be called in other place than
// SendThreadProc in the future.
_DBG_ASSERT( pMultiTarget );
CInLock<CFilterProxyManager> il(this);
return pMultiTarget->DeliverEvent(lNumToSend, apEvents, aTargets, lSDLength, pSD); }
ULONG CFilterProxyManager::XProxy::AddRef() { return m_pObject->AddRefProxy(); }
ULONG CFilterProxyManager::XProxy::Release() { return m_pObject->ReleaseProxy(); }
HRESULT CFilterProxyManager::XProxy::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown || riid == IID_IWbemFilterProxy || riid == IID_IWbemLocalFilterProxy) { *ppv = (IWbemLocalFilterProxy*)this; AddRef(); return S_OK; } else { return E_NOINTERFACE; } }
HRESULT CFilterProxyManager::XProxy::Initialize(IWbemMetaData* pMetaData, IWbemMultiTarget* pMultiTarget) { ENTER_API_CALL
return m_pObject->Initialize(pMetaData, pMultiTarget);
EXIT_API_CALL } HRESULT CFilterProxyManager::XProxy::Lock() // Deprecated ?
{ ENTER_API_CALL
return m_pObject->Lock();
EXIT_API_CALL } HRESULT CFilterProxyManager::XProxy::Unlock() // Deprecated ?
{ ENTER_API_CALL
return m_pObject->Unlock();
EXIT_API_CALL } HRESULT CFilterProxyManager::XProxy::AddFilter(IWbemContext* pContext, LPCWSTR wszQuery, WBEM_REMOTE_TARGET_ID_TYPE idFilter) { ENTER_API_CALL
return m_pObject->AddFilter(pContext, wszQuery, idFilter);
EXIT_API_CALL } HRESULT CFilterProxyManager::XProxy::RemoveFilter(IWbemContext* pContext, WBEM_REMOTE_TARGET_ID_TYPE idFilter) { ENTER_API_CALL
return m_pObject->RemoveFilter(pContext, idFilter); EXIT_API_CALL } HRESULT CFilterProxyManager::XProxy::RemoveAllFilters(IWbemContext* pContext) { ENTER_API_CALL
return m_pObject->RemoveAllFilters(pContext);
EXIT_API_CALL }
HRESULT CFilterProxyManager::XProxy::AddDefinitionQuery(IWbemContext* pContext, LPCWSTR wszQuery) { ENTER_API_CALL
return m_pObject->AddDefinitionQuery(pContext, wszQuery);
EXIT_API_CALL }
HRESULT CFilterProxyManager::XProxy::AllowUtilizeGuarantee() { ENTER_API_CALL
return m_pObject->AllowUtilizeGuarantee();
EXIT_API_CALL }
HRESULT CFilterProxyManager::XProxy::RemoveAllDefinitionQueries( IWbemContext* pContext) { ENTER_API_CALL
return m_pObject->RemoveAllDefinitionQueries(pContext);
EXIT_API_CALL } HRESULT CFilterProxyManager::XProxy::Disconnect() { ENTER_API_CALL
return m_pObject->Disconnect();
EXIT_API_CALL }
HRESULT CFilterProxyManager::XProxy::SetStub(IWbemFilterStub* pStub) { return m_pObject->SetStub(pStub); }
HRESULT CFilterProxyManager::XProxy::LocalAddFilter(IWbemContext* pContext, LPCWSTR wszQuery, void* pExp, WBEM_REMOTE_TARGET_ID_TYPE Id) { return m_pObject->AddFilter(pContext, wszQuery, (QL_LEVEL_1_RPN_EXPRESSION*)pExp, Id); }
HRESULT CFilterProxyManager::XProxy::GetMainSink(IWbemEventSink** ppSink) { *ppSink = m_pObject->GetMainProxy(); if(*ppSink) { (*ppSink)->AddRef(); return S_OK; } else return E_UNEXPECTED; }
void CFilterProxyManager::CalcMaxSendLatency() { LockBatching();
DWORD dwLatency = 0xFFFFFFFF;
for (CLatencyMapItor i = m_mapLatencies.begin(); i != m_mapLatencies.end(); i++) { if ((*i).second < dwLatency) dwLatency = (*i).second; }
m_dwMaxSendLatency = dwLatency;
UnlockBatching(); }
HRESULT CFilterProxyManager::SetProxyLatency(CFilterProxy *pProxy, DWORD dwLatency) { LockBatching();
BOOL bWasEmpty = m_mapLatencies.size() == 0; // Add this proxy.
m_mapLatencies[pProxy] = dwLatency;
HRESULT hr = S_OK;
// If our map was previously empty, start the send thread.
if ( bWasEmpty ) { m_dwMaxSendLatency = dwLatency;
_DBG_ASSERT( NULL == m_hthreadSend );
if ( NULL == m_hthreadSend ) { _DBG_ASSERT( NULL == m_pMultiTargetStream );
//
// IWbemMultiTarget interface pointer is mashaled to make the
// interface pointer available for cross apartment access
//
hr = CoMarshalInterThreadInterfaceInStream( IID_IWbemMultiTarget, m_pMultiTarget, &m_pMultiTargetStream );
if ( SUCCEEDED( hr ) ) { if ( FALSE == StartSendThread( ) ) { ERRORTRACE((LOG_ESS, "Failed to set proxy latency due to thread creation error : 0x%X\n", GetLastError( ) ) ); m_pMultiTargetStream->Release( ); m_pMultiTargetStream = NULL; hr = E_FAIL; } } else { m_pMultiTargetStream = NULL; ERRORTRACE((LOG_ESS, "Failed to set proxy latency due to marshaling error : 0x%X\n", hr ) ); } } } else { // If dwLatency is smaller than m_dwMaxSendLatency, set
// m_dwMaxSendLatency to the new smallest value.
if (dwLatency < m_dwMaxSendLatency) m_dwMaxSendLatency = dwLatency; } UnlockBatching();
return hr; }
void CFilterProxyManager::RemoveProxyLatency(CFilterProxy *pProxy) { LockBatching();
// Try to find the proxy.
CLatencyMapItor item = m_mapLatencies.find(pProxy);
// Did we find it?
if (item != m_mapLatencies.end()) { // Remove it.
m_mapLatencies.erase(item);
// If there are no more proxies that care about batching, stop the
// send thread.
if (m_mapLatencies.size() == 0) StopSendThread(); else { DWORD dwLatency = (*item).second;
// If the latency value we just removed is the same as
// m_dwMaxSendLatency, recalc m_dwMaxSendLatency.
if (dwLatency == m_dwMaxSendLatency) CalcMaxSendLatency(); } }
UnlockBatching(); }
BOOL CFilterProxyManager::StartSendThread() { LockBatching();
if ( NULL == m_hthreadSend ) { DWORD dwID;
do { m_heventDone = CreateEvent( NULL, FALSE, FALSE, NULL ); if ( NULL == m_heventDone ) { break; }
m_heventBufferNotFull = CreateEvent( NULL, TRUE, TRUE, NULL ); if ( NULL == m_heventBufferNotFull ) { break; }
m_heventBufferFull = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( NULL == m_heventBufferFull ) { break; }
m_heventEventsPending = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( NULL == m_heventEventsPending ) { break; }
m_hthreadSend = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) SendThreadProc, this, 0, &dwID ); } while( FALSE );
if ( NULL == m_hthreadSend ) { if (m_heventDone) { CloseHandle(m_heventDone); m_heventDone = NULL; }
if (m_heventBufferNotFull) { CloseHandle(m_heventBufferNotFull); m_heventBufferNotFull = NULL; }
if (m_heventBufferFull) { CloseHandle(m_heventBufferFull); m_heventBufferFull = NULL; }
if (m_heventEventsPending) { CloseHandle(m_heventEventsPending); m_heventEventsPending = NULL; } } }
UnlockBatching();
return ( NULL != m_hthreadSend ); }
void CFilterProxyManager::StopSendThread() { LockBatching();
if (m_hthreadSend && m_heventDone) { SetEvent(m_heventDone); WaitForSingleObject(m_hthreadSend, 3000); CloseHandle(m_hthreadSend); m_hthreadSend = NULL; }
if (m_heventDone) { CloseHandle(m_heventDone); m_heventDone = NULL; }
if (m_heventBufferNotFull) { CloseHandle(m_heventBufferNotFull); m_heventBufferNotFull = NULL; }
if (m_heventBufferFull) { CloseHandle(m_heventBufferFull); m_heventBufferFull = NULL; }
if (m_heventEventsPending) { CloseHandle(m_heventEventsPending); m_heventEventsPending = NULL; }
UnlockBatching(); }
DWORD WINAPI CFilterProxyManager::SendThreadProc(CFilterProxyManager *pThis) { HANDLE hWait[2] = { pThis->m_heventDone, pThis->m_heventEventsPending }, hwaitSendLatency[2] = { pThis->m_heventDone, pThis->m_heventBufferFull }, heventBufferNotFull = pThis->m_heventBufferNotFull; HRESULT hres; IWbemMultiTarget * pMultiTarget = NULL;
_DBG_ASSERT( pThis->m_pMultiTargetStream );
if ( NULL == pThis->m_pMultiTargetStream ) { return 1; }
CoInitializeEx( NULL, COINIT_MULTITHREADED );
//
// IWbemMultiTarget interface pointer is unmarshaled to use in this
// thread (in case of cross apartment).
//
hres = CoGetInterfaceAndReleaseStream( pThis->m_pMultiTargetStream, IID_IWbemMultiTarget, ( void ** )&pMultiTarget );
if( FAILED( hres ) ) { ERRORTRACE((LOG_ESS, "Failed to run batching thread due to unmarshaling errors: 0x%X\n", hres)); // pThis->m_pMultiTargetStream->Release( );
pThis->m_pMultiTargetStream = NULL; CoUninitialize( ); return 1; }
pThis->m_pMultiTargetStream = NULL;
_DBG_ASSERT( pMultiTarget );
while (WaitForMultipleObjects(2, hWait, FALSE, INFINITE) != 0) { // If we have a send latency, wait for that time or until the send
// buffer is full. If the done event fires, get out.
if (pThis->m_dwMaxSendLatency) { if (WaitForMultipleObjects(2, hwaitSendLatency, FALSE, pThis->m_dwMaxSendLatency) == 0) break;
// Reset m_heventBufferFull.
ResetEvent(hwaitSendLatency[1]); }
CInCritSec csBuffer(&pThis->m_csBuffer); int nItems = pThis->m_batch.GetItemCount(); hres = pThis->DeliverEventMT( nItems, pThis->m_batch.GetObjs(), pThis->m_batch.GetTargets(), 0, &CFilterProxy::mstatic_EmptySD, pMultiTarget);
// Increment this so the filter proxies will know to clear out their
// buffer size when they next get an event to batch.
pThis->m_dwLastSentStamp++;
pThis->m_batch.RemoveAll();
SetEvent(heventBufferNotFull);
// Reset m_heventEventsPending
ResetEvent(hWait[1]); }
// Make sure our batch buffer is empty before we exit.
CInCritSec csBuffer(&pThis->m_csBuffer); int nItems = pThis->m_batch.GetItemCount(); if ( nItems ) { pThis->DeliverEventMT( nItems, pThis->m_batch.GetObjs(), pThis->m_batch.GetTargets(), 0, &CFilterProxy::mstatic_EmptySD, pMultiTarget); }
CoUninitialize( );
return 0; }
DWORD CFilterProxyManager::GetLastSentStamp() { return m_dwLastSentStamp; }
//*****************************************************************************
//*****************************************************************************
//
// FILTER PROXY
//
//*****************************************************************************
//*****************************************************************************
CTimeKeeper CFilterProxy::mstatic_TimeKeeper; BYTE CFilterProxy::mstatic_EmptySD = 0;
CFilterProxy::CFilterProxy(CFilterProxyManager* pManager, IUnknown* pCallback) : m_lRef(0), m_pManager(pManager), m_pMetaData(NULL), m_lSDLength(0), m_pSD(&mstatic_EmptySD), m_pProvider(NULL), m_pQuerySink(NULL), m_bRunning(false), m_typeBatch(WBEM_FLAG_MUST_NOT_BATCH), m_bUtilizeGuarantee(false), m_dwCurrentBufferSize(0), m_bBatching(FALSE), m_wSourceVersion(0), m_wAppliedSourceVersion(0) { m_SourceDefinition.SetBool(FALSE); if(m_pManager) { m_pManager->AddRef(); m_pManager->GetMetaData(&m_pMetaData); }
if(pCallback) { pCallback->QueryInterface(IID_IWbemEventProvider, (void**)&m_pProvider); pCallback->QueryInterface(IID_IWbemEventProviderQuerySink, (void**)&m_pQuerySink); } }
CFilterProxy::~CFilterProxy() { if (m_pMetaData) m_pMetaData->Release();
if (m_pManager) m_pManager->Release(); }
ULONG STDMETHODCALLTYPE CFilterProxy::AddRef() { return InterlockedIncrement(&m_lRef); }
ULONG STDMETHODCALLTYPE CFilterProxy::Release() { //
// CFilterProxy is deleted by CFilterProxyManager --- it never goes away
// on a Release
//
long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) { //
// Inform the manager that we are no longer needed. This call can
// destroy this object!
//
m_pManager->RemoveProxy(this); }
return lRef; }
HRESULT STDMETHODCALLTYPE CFilterProxy::QueryInterface(REFIID riid, void** ppv) { if( riid == IID_IUnknown || riid == IID_IWbemObjectSink || riid == IID_IWbemEventSink) { *ppv = (IWbemEventSink*)this; } else if(riid == IID_IMarshal) { *ppv = (IMarshal*)this; } else return E_NOINTERFACE;
((IUnknown*)*ppv)->AddRef(); return S_OK; } HRESULT CFilterProxy::Lock() { return m_pManager->Lock(); }
HRESULT CFilterProxy::Unlock() { return m_pManager->Unlock(); }
HRESULT CFilterProxy::SetRunning() { HRESULT hres;
bool bActive = false; IWbemEventProvider* pProvider = NULL;
{ CInCritSec ics(&m_cs);
if(m_bRunning) return WBEM_S_FALSE; else { m_bRunning = true; if(m_pProvider) { bActive = (IsActive() == WBEM_S_NO_ERROR); pProvider = m_pProvider; pProvider->AddRef(); } } }
//
// If here, we are just now marking it for running. Notify the callback if
// there are any sinks
//
if(bActive && pProvider) { hres = pProvider->ProvideEvents(NULL, WBEM_FLAG_START_PROVIDING); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Restricted sink refused to stop " "error code 0x%X\n", hres)); } }
return WBEM_S_NO_ERROR; }
HRESULT CFilterProxy::AddFilter(IWbemContext* pContext, LPCWSTR wszQuery, QL_LEVEL_1_RPN_EXPRESSION* pExp, WBEM_REMOTE_TARGET_ID_TYPE idFilter) { HRESULT hres;
// Compile the query
// =================
CContextMetaData MetaData(m_pMetaData, pContext);
CEvalTree Tree; hres = Tree.CreateFromQuery( &MetaData, pExp, WBEM_FLAG_MANDATORY_MERGE ); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Filter proxy unable to parse %S, " "error code: %X\n", wszQuery, hres)); return hres; } //
// merge the query into the rest of the filter.
//
{ CInCritSec ics(&m_cs);
if ( m_bUtilizeGuarantee ) { //
// Utilize source definition
// =========================
//
// assert that our source definition hasn't changed since the last
// time a filter was added. This would be bad, since the tree
// doesn't account for the new source queries. Also assert that
// the source tree is valid and is not empty. ( These last two may
// have to be removed in the future. For now they shouldn't be
// false )
//
_ESSCLI_ASSERT( m_wAppliedSourceVersion == 0 || m_wAppliedSourceVersion == m_wSourceVersion ); _ESSCLI_ASSERT( m_SourceDefinition.IsValid() ); _ESSCLI_ASSERT( !m_SourceDefinition.IsFalse() ); hres = Tree.UtilizeGuarantee(m_SourceDefinition, &MetaData); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Filter proxy unable to utilize guarantee for %S, " "error code: %X\n", wszQuery, hres)); return hres; }
//
// Check if anything is left of it
//
if(!Tree.IsValid()) { //
// Utilization of the guarantee shows that this filter cannot
// be satisftied by events coming through this proxy
//
return WBEM_S_FALSE; } }
//
// Add consumer information to it
//
Tree.Rebase((QueryID)idFilter);
#ifdef DUMP_DEBUG_TREES
FILE* f = fopen("c:\\try.log", "a"); fprintf(f, "\n\nAdding filter\n"); Tree.Dump(f); fprintf(f, " to existing filter: \n"); m_Filter.Dump(f); #endif
hres = m_Filter.CombineWith(Tree, &MetaData, EVAL_OP_COMBINE); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Filter proxy unable to combine %S with the " "rest, error code: %X\n", wszQuery, hres)); return hres; }
m_wAppliedSourceVersion = m_wSourceVersion; }
//
// Now, we need to notify the provider of a new filter being issued
//
IWbemEventProviderQuerySink* pQuerySink = NULL; IWbemEventProvider* pProvider = NULL;
{ CInCritSec ics(&m_cs);
if(m_pQuerySink) { pQuerySink = m_pQuerySink; pQuerySink->AddRef(); }
if(m_pProvider) { pProvider = m_pProvider; pProvider->AddRef(); } }
//
// Call provider's NewQuery, if supported
//
if(pQuerySink) { hres = pQuerySink->NewQuery(idFilter, L"WQL", (LPWSTR)wszQuery); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Restricted sink refused consumer " "registration query %S: error code 0x%X\n", wszQuery, hres));
// Too bad --- restricted sinks cannot veto subscriptions
} }
//
// If we are adding this filter to a running proxy, and this is the very
// first filter on it, we should call ProvideEvents immediately. Not so if
// we are configuring a proxy that is not running yet --- in that case, we
// need to wait until all outstanding filters have been put in place
//
if(m_bRunning && (IsActive() == WBEM_S_FALSE) && pProvider) { hres = pProvider->ProvideEvents((IWbemObjectSink*)this, WBEM_FLAG_START_PROVIDING);
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Restricted sink refused a call to " "ProvideEvents with 0x%X\n", hres)); } }
#ifdef DUMP_DEBUG_TREES
fprintf(f, " to obtain: \n"); m_Filter.Dump(f); fclose(f); #endif
return WBEM_S_NO_ERROR; }
HRESULT CFilterProxy::RemoveFilter(IWbemContext* pContext, WBEM_REMOTE_TARGET_ID_TYPE idFilter) { HRESULT hres;
IWbemEventProviderQuerySink* pQuerySink = NULL; IWbemEventProvider* pProvider = NULL;
bool bActive; { CInCritSec ics(&m_cs);
if(m_pQuerySink) { pQuerySink = m_pQuerySink; pQuerySink->AddRef(); }
if(m_pProvider) { pProvider = m_pProvider; pProvider->AddRef(); } hres = m_Filter.RemoveIndex(idFilter); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Unable to remove index %d from the filter " "proxy\n", idFilter)); return hres; } CContextMetaData MetaData(m_pMetaData, pContext);
hres = m_Filter.Optimize(&MetaData); if(FAILED(hres)) return hres;
bActive = (IsActive() == WBEM_S_NO_ERROR); }
//
// Call provider's NewQuery, if supported
//
if(pQuerySink) { hres = pQuerySink->CancelQuery(idFilter); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Restricted sink refused consumer " "registration query cancellation: error code 0x%X\n", hres)); } }
//
// If we are left with no queries, notify provider of that fact
//
if(!bActive && pProvider) { hres = pProvider->ProvideEvents(NULL, WBEM_FLAG_STOP_PROVIDING); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Restricted sink refused to stop " "error code 0x%X\n", hres)); } } #ifdef DUMP_DEBUG_TREES
FILE* f = fopen("c:\\try.log", "a"); fprintf(f, "Removed at %d to obtain: \n", idFilter); m_Filter.Dump(f); fclose(f); #endif
return WBEM_S_NO_ERROR; }
HRESULT CFilterProxy::RemoveAllFilters(IWbemContext* pContext) { CInCritSec ics(&m_cs); m_wAppliedSourceVersion = 0; if(!m_Filter.Clear()) return WBEM_E_OUT_OF_MEMORY; return WBEM_S_NO_ERROR; } HRESULT CFilterProxy::AllowUtilizeGuarantee() { //
// ess shouldn't be calling this function if the tree is invalid.
//
_DBG_ASSERT( m_SourceDefinition.IsValid() );
//
// ess thinks its o.k. to utilize the guarantee, however there are cases
// where the soruce definition could still be false ( e.g. when there are
// no source definition queries or when all of the source definition
// queries are contradictions ).
//
CInCritSec ics(&m_cs);
if ( !m_SourceDefinition.IsFalse() ) { m_bUtilizeGuarantee = true; }
return WBEM_S_NO_ERROR; }
HRESULT CFilterProxy::AddDefinitionQuery( IWbemContext* pContext, LPCWSTR wszQuery ) { HRESULT hres;
// Compile the query
// =================
CContextMetaData MetaData(m_pMetaData, pContext);
CEvalTree Tree; hres = Tree.CreateFromQuery( &MetaData, wszQuery, WBEM_FLAG_MANDATORY_MERGE, 0x7FFFFFFF ); // no limit
if(FAILED(hres)) { return hres; }
{ CInCritSec ics(&m_cs);
//
// we shouldn't be adding definition queries when there are currently
// existing filters.
//
_ESSCLI_ASSERT( m_Filter.IsFalse() );
// Merge the query into the rest
// =============================
hres = m_SourceDefinition.CombineWith(Tree, &MetaData, EVAL_OP_OR, WBEM_FLAG_MANDATORY_MERGE); if(FAILED(hres)) return hres;
m_wSourceVersion++; }
return WBEM_S_NO_ERROR; }
HRESULT CFilterProxy::RemoveAllDefinitionQueries( IWbemContext* pContext) { CInCritSec ics(&m_cs);
m_wSourceVersion = 0; m_SourceDefinition.SetBool(FALSE); m_bUtilizeGuarantee = false;
return WBEM_S_NO_ERROR; }
HRESULT CFilterProxy::ProcessOne( IUnknown* pUnk, long lSDLength, BYTE* pSD ) { //
// NOTE: not in a critical section yet
//
HRESULT hres;
//
// Check overall validity
//
if( pUnk == NULL ) { ERRORTRACE((LOG_ESS, "Event provider returned a NULL event!\n")); return WBEM_E_INVALID_PARAMETER; } CWbemObject* pObj = (CWbemObject*)(IWbemClassObject*)pUnk; if( pObj->IsObjectInstance() != WBEM_S_NO_ERROR ) { ERRORTRACE((LOG_ESS, "CLASS object received from event provider!\n")); return WBEM_E_INVALID_PARAMETER; }
//
// Run the event through the filter
//
CSortedArray aTrues, aSourceTrues; CFilterProxyManager* pManager = NULL;
{ CInCritSec ics(&m_cs); hres = FilterEvent( pObj, aTrues );
if ( hres == WBEM_S_NO_ERROR ) { _DBG_ASSERT( aTrues.Size() > 0 ); } else { return hres; }
pManager = m_pManager; if( pManager ) { pManager->AddRef(); } else { return WBEM_S_FALSE; } }
CReleaseMe rm2(pManager);
//
// the event has made it through the filter ..
//
SetGenerationTime(pObj);
if (IsBatching()) { BatchEvent((IWbemClassObject*) pUnk, &aTrues);
hres = S_OK; } else { // Some delivery is required --- construct the blob and the targets
// ================================================================
WBEM_REM_TARGETS RemTargets; if(!TempSetTargets(&RemTargets, &aTrues)) return WBEM_E_OUT_OF_MEMORY; hres = pManager->DeliverEvent(1, (IWbemClassObject**)&pObj, &RemTargets, lSDLength, pSD); TempClearTargets(&RemTargets);
if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Filter stub failed to process an event: " "0x%X\n", hres)); } }
return hres; }
void CFilterProxy::SetGenerationTime(_IWmiObject* pObj) { mstatic_TimeKeeper.DecorateObject(pObj); }
void CFilterProxyManager::AddEvent( IWbemClassObject *pObj, CSortedArray *pTrues) { LockBatching();
BOOL bWasEmpty = m_batch.GetItemCount() == 0;
m_batch.AddEvent(pObj, pTrues);
if (bWasEmpty) SetEvent(m_heventEventsPending);
UnlockBatching(); }
void CFilterProxyManager::WaitForEmptyBatch() { LockBatching();
// Once we get the lock and the batch has already been cleared out, we
// don't need to do anything else.
if (m_batch.GetItemCount() == 0) { UnlockBatching();
return; }
// We need to wait for the send thread to finish sending what's
// in our buffer.
// Wake up the send latency thread if necessary.
if (m_dwMaxSendLatency) SetEvent(m_heventBufferFull); // So we'll block until the send thread sets the event.
ResetEvent(m_heventBufferNotFull);
UnlockBatching();
WaitForSingleObject(m_heventBufferNotFull, INFINITE); }
void CFilterProxy::BatchEvent( IWbemClassObject *pObj, CSortedArray *pTrues) { BOOL bRet = FALSE; _IWmiObject *pWmiObj = (_IWmiObject*) pObj; DWORD dwObjSize = 0;
pWmiObj->GetObjectMemory( NULL, 0, &dwObjSize);
CInCritSec ics(&m_cs);
// See if the manager has sent off its batch of events since we last
// batched an event.
if (m_dwLastSentStamp != m_pManager->GetLastSentStamp()) m_dwCurrentBufferSize = 0;
// See if we have enough room to add our event.
if (m_dwCurrentBufferSize >= m_dwMaxBufferSize) { m_pManager->WaitForEmptyBatch(); m_dwCurrentBufferSize = 0; }
m_dwCurrentBufferSize += dwObjSize;
m_dwLastSentStamp = m_pManager->GetLastSentStamp(); m_pManager->AddEvent(pObj, pTrues); }
HRESULT CFilterProxy::FilterEvent( _IWmiObject* pObj, CSortedArray& raTrues ) { HRESULT hr;
//
// evaluate
//
try { //
// this code is in a try catch because if a provider generates
// events that it has not registered to, then we do bad things to
// class objects. A potential fix could be do extra checking on
// our part, but is expensive when using the public interfaces. A
// more advantageous fix should be making the class object code
// perform the checking for us ( e.g. when we ask for a property
// using an invalid handle, etc ). It can do this checking much
// faster. When this checking is performed by the class object
// code, we should remove this try catch. see RAID 166026
//
hr = m_Filter.Evaluate( pObj, raTrues ); } catch( ... ) { //
// check to see if the provider is generating an event its not
// supposed to. If so, then handle AV and return error, else
// rethrow - there's something else wrong.
//
CSortedArray aSourceTrues;
hr = m_SourceDefinition.Evaluate( pObj, aSourceTrues ); if ( SUCCEEDED(hr) && aSourceTrues.Size() == 0 ) { ERRORTRACE((LOG_ESS, "Filter Proxy encountered case where " "event provider is signaling events that are not " "covered by its registration!!\n")); hr = WBEM_E_INVALID_OBJECT; } else { throw; } }
//
// check events that make it through the filter against source definition.
// if we're not utilizing guarantee, then there's no need to check the
// event against the source definition because its already factored into
// the filter.
//
if (SUCCEEDED(hr) && raTrues.Size() == 0 ) { hr = WBEM_S_FALSE; } else if ( SUCCEEDED(hr) && m_bUtilizeGuarantee ) { //
// run the event through the source tree to ensure that the
// provider is providing the events its supposed to.
//
CSortedArray aSourceTrues;
hr = m_SourceDefinition.Evaluate( pObj, aSourceTrues );
if ( SUCCEEDED(hr) && aSourceTrues.Size() == 0 ) { ERRORTRACE((LOG_ESS, "Filter Proxy encountered case where " "event provider is signaling events that are not " "covered by its registration!!\n")); hr = WBEM_E_INVALID_OBJECT; } }
return hr; }
HRESULT CFilterProxy::BatchMany(long nEvents, IUnknown **ppObjects) { HRESULT hr = S_OK;
for ( long i = 0; i < nEvents && SUCCEEDED(hr); i++ ) { //
// Check overall validity
//
if( ppObjects[i] == NULL ) { ERRORTRACE((LOG_ESS, "Event provider returned a NULL event!\n")); return WBEM_E_INVALID_PARAMETER; } CWbemObject *pObj = (CWbemObject*)(IWbemClassObject*)ppObjects[i]; if( pObj->IsObjectInstance() != WBEM_S_NO_ERROR ) { ERRORTRACE((LOG_ESS, "CLASS object received from event provider!\n")); return WBEM_E_INVALID_PARAMETER; }
//
// Run the event through the filter
//
CInCritSec ics(&m_cs); CSortedArray aTrues; hr = FilterEvent( pObj, aTrues ); if ( hr == WBEM_S_NO_ERROR ) { _DBG_ASSERT( aTrues.Size() > 0 );
//
// Delivery is required --- add this event to the list
//
SetGenerationTime(pObj); BatchEvent(pObj, &aTrues); } }
return hr; }
class CDeleteTargetsArray { protected: WBEM_REM_TARGETS *m_pData; int *m_piSize;
public: CDeleteTargetsArray(WBEM_REM_TARGETS *pData, int *piSize) : m_pData(pData), m_piSize(piSize) { }
~CDeleteTargetsArray() { int nSize = *m_piSize;
for (DWORD i = 0; i < nSize; i++) TempClearTargets(m_pData + i); } };
HRESULT CFilterProxy::ProcessMany(long lNumObjects, IUnknown** apObjects, long lSDLength, BYTE* pSD) { //
// NOTE: not in critical section
//
HRESULT hres;
if (IsBatching()) return BatchMany(lNumObjects, apObjects);
//
// Allocate appropriate arrays on the stack
//
CTempArray<IWbemClassObject*> apEventsToSend; INIT_TEMP_ARRAY(apEventsToSend, lNumObjects); if(apEventsToSend == NULL) return WBEM_E_OUT_OF_MEMORY;
CTempArray<WBEM_REM_TARGETS> aTargetsToSend; INIT_TEMP_ARRAY(aTargetsToSend, lNumObjects); if(aTargetsToSend == NULL) return WBEM_E_OUT_OF_MEMORY;
int lNumToSend = 0;
// Make sure the array gets cleaned up.
CDeleteTargetsArray deleteMe(aTargetsToSend, &lNumToSend); //
// Iterate over events supplied and move those that need to be delivered
// into delivery arrays
//
CFilterProxyManager* pManager = NULL; { //
// We could choose a smaller window, but I am betting that the cost of
// entering and exiting the cs many times will outweigh the benefits
// of slightly smaller windows
//
CInCritSec ics(&m_cs); for(long i = 0; i < lNumObjects; i++) { //
// Check overall validity
//
if( apObjects[i] == NULL ) { ERRORTRACE((LOG_ESS, "Event provider returned a NULL event!\n")); return WBEM_E_INVALID_PARAMETER; } CWbemObject *pObj = (CWbemObject*)(IWbemClassObject*)apObjects[i]; if( pObj->IsObjectInstance() != WBEM_S_NO_ERROR ) { ERRORTRACE((LOG_ESS, "CLASS object received from event provider!\n")); return WBEM_E_INVALID_PARAMETER; }
//
// Run the event through the filter
//
CSortedArray aTrues; hres = FilterEvent( pObj, aTrues );
if ( hres == WBEM_S_FALSE ) { ; } else if ( hres == WBEM_S_NO_ERROR ) { _DBG_ASSERT( aTrues.Size() > 0 );
//
// Delivery is required --- add this event to the list
//
SetGenerationTime(pObj); apEventsToSend[lNumToSend] = pObj;
if(!TempSetTargets(aTargetsToSend + lNumToSend, &aTrues)) return WBEM_E_OUT_OF_MEMORY; lNumToSend++; } else { return hres; } } //
// If any events need to be delivered, get the delivery pointer
//
if(lNumToSend > 0) { pManager = m_pManager; if(pManager) pManager->AddRef(); else return WBEM_S_FALSE; } } CReleaseMe rm1(pManager);
//
// If any events need to be delivered, deliver
//
if(lNumToSend > 0) { hres = pManager->DeliverEvent(lNumToSend, apEventsToSend, aTargetsToSend, lSDLength, pSD); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Filter stub failed to process an event: " "error code %X\n", hres)); }
return hres; }
return WBEM_S_FALSE; }
HRESULT STDMETHODCALLTYPE CFilterProxy::Indicate(long lNumObjects, IWbemClassObject** apObjects) { return IndicateWithSD(lNumObjects, (IUnknown**)apObjects, m_lSDLength, m_pSD); }
HRESULT STDMETHODCALLTYPE CFilterProxy::SetStatus(long lFlags, HRESULT hResult, BSTR strResult, IWbemClassObject* pErrorObj) { return m_pManager->SetStatus(lFlags, hResult, strResult, pErrorObj); }
STDMETHODIMP CFilterProxy::IndicateWithSD(long lNumObjects, IUnknown** apObjects, long lSDLength, BYTE* pSD) { if(lNumObjects <= 0 || apObjects == NULL) return WBEM_E_INVALID_PARAMETER;
if(pSD == NULL) { //
// Use proxy defaults
//
lSDLength = m_lSDLength; pSD = m_pSD; }
try { //
// Special-case single event
//
if(lNumObjects == 1) return ProcessOne(*apObjects, lSDLength, pSD); else return ProcessMany(lNumObjects, apObjects, lSDLength, pSD);
} catch(...) { return WBEM_E_OUT_OF_MEMORY; } }
STDMETHODIMP CFilterProxy::IsActive() { CInCritSec ics(&m_cs);
return (m_Filter.IsFalse()?WBEM_S_FALSE:WBEM_S_NO_ERROR); return WBEM_S_NO_ERROR; }
STDMETHODIMP CFilterProxy::SetSinkSecurity( long lSDLength, BYTE* pSD) { CInCritSec ics(&m_cs);
//
// Check for validity
//
if(lSDLength < 0) return WBEM_E_INVALID_PARAMETER;
if(lSDLength > 0) { SECURITY_DESCRIPTOR* pDesc = (SECURITY_DESCRIPTOR*)pSD; if(!IsValidSecurityDescriptor(pDesc)) return WBEM_E_INVALID_PARAMETER; if(pDesc->Owner == NULL || pDesc->Group == NULL) return WBEM_E_INVALID_PARAMETER; if(GetSecurityDescriptorLength(pSD) != (DWORD)lSDLength) return WBEM_E_INVALID_PARAMETER; } else { if(pSD != NULL) return WBEM_E_INVALID_PARAMETER; } //
// Store the SD in the proxy
//
if(m_pSD && m_pSD != &mstatic_EmptySD) delete [] m_pSD;
if(lSDLength) { m_pSD = new BYTE[lSDLength]; if(m_pSD == NULL) return WBEM_E_OUT_OF_MEMORY; memcpy(m_pSD, pSD, lSDLength); } else { //
// Cannot let m_pSD be NULL
//
m_pSD = &mstatic_EmptySD; } m_lSDLength = lSDLength;
return WBEM_S_NO_ERROR; }
STDMETHODIMP CFilterProxy::GetRestrictedSink( long lNumQueries, const LPCWSTR* awszQueries, IUnknown* pCallback, IWbemEventSink** ppSink) { return m_pManager->GetRestrictedSink(lNumQueries, awszQueries, pCallback, ppSink); }
STDMETHODIMP CFilterProxy::SetBatchingParameters( LONG lFlags, DWORD dwMaxBufferSize, DWORD dwMaxSendLatency) { HRESULT hr = S_OK; CInCritSec ics(&m_cs);
switch(lFlags) { // TODO: WBEM_FLAG_BATCH_IF_NEEDED currently works the same as
// WBEM_FLAG_MUST_NOT_BATCH. At some point this needs allow
// subscriptions to determine the batching behavior.
case WBEM_FLAG_BATCH_IF_NEEDED: case WBEM_FLAG_MUST_NOT_BATCH: m_typeBatch = (WBEM_BATCH_TYPE) lFlags; m_pManager->RemoveProxyLatency(this); m_bBatching = FALSE; break;
case WBEM_FLAG_MUST_BATCH: m_typeBatch = (WBEM_BATCH_TYPE) lFlags; m_dwMaxSendLatency = dwMaxSendLatency; m_dwMaxBufferSize = dwMaxBufferSize; m_dwLastSentStamp = m_pManager->GetLastSentStamp(); hr = m_pManager->SetProxyLatency(this, dwMaxSendLatency); m_bBatching = TRUE; break;
default: hr = WBEM_E_INVALID_PARAMETER; break; }
return hr; }
// Assumes pMainProxy is locked
HRESULT CFilterProxy::TransferFiltersFromMain(CFilterProxy* pMain) { HRESULT hres;
//
// Move all the normal filters
//
try { m_Filter = pMain->m_Filter; } catch(CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } if ( m_bUtilizeGuarantee ) { // Utilize source definition
// =========================
CContextMetaData MetaData(m_pMetaData, NULL); hres = m_Filter.UtilizeGuarantee(m_SourceDefinition, &MetaData); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Filter proxy unable to utilize guarantee for" " a new proxy; error code: %X\n", hres)); return hres; } }
return WBEM_S_NO_ERROR; }
STDMETHODIMP CFilterProxy::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext, void* pvReserved, DWORD mshlFlags, CLSID* pClsid) { return m_pManager->GetUnmarshalClass(riid, pv, dwDestContext, pvReserved, mshlFlags, pClsid); }
STDMETHODIMP CFilterProxy::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext, void* pvReserved, DWORD mshlFlags, ULONG* plSize) { return m_pManager->GetMarshalSizeMax(riid, pv, dwDestContext, pvReserved, mshlFlags, plSize); }
STDMETHODIMP CFilterProxy::MarshalInterface(IStream* pStream, REFIID riid, void* pv, DWORD dwDestContext, void* pvReserved, DWORD mshlFlags) { return m_pManager->MarshalInterface(pStream, riid, pv, dwDestContext, pvReserved, mshlFlags); }
/////////////////////////////////////////////////////////////////////////////
// CEventBatch
#define INIT_SIZE 32
#define GROW_SIZE 32
CEventBatch::CEventBatch() : m_ppObjs(NULL), m_pTargets(NULL), m_nItems(0), m_dwSize(0) { m_ppObjs = new IWbemClassObject*[INIT_SIZE]; if (!m_ppObjs) throw CX_MemoryException();
m_pTargets = new WBEM_REM_TARGETS[INIT_SIZE]; if (!m_pTargets) throw CX_MemoryException();
m_dwSize = INIT_SIZE; }
CEventBatch::~CEventBatch() { RemoveAll();
if (m_ppObjs) delete [] m_ppObjs;
if (m_pTargets) delete [] m_pTargets; }
BOOL CEventBatch::EnsureAdditionalSize(DWORD nAdditionalNeeded) { if (m_nItems + nAdditionalNeeded > m_dwSize) { DWORD nNewSize = m_nItems + nAdditionalNeeded + GROW_SIZE; IWbemClassObject **ppNewObjs; WBEM_REM_TARGETS *pNewTargets;
ppNewObjs = new IWbemClassObject*[nNewSize]; if (!ppNewObjs) throw CX_MemoryException();
pNewTargets = new WBEM_REM_TARGETS[nNewSize]; if (!pNewTargets) { delete [] ppNewObjs; throw CX_MemoryException(); }
// Copy the data from the old pointers to the new pointers.
memcpy(ppNewObjs, m_ppObjs, m_nItems * sizeof(ppNewObjs[0])); memcpy(pNewTargets, m_pTargets, m_nItems * sizeof(pNewTargets[0]));
// Get rid of the old pointers.
delete [] m_ppObjs; delete [] m_pTargets;
// Set our member pointers with the new pointers.
m_ppObjs = ppNewObjs; m_pTargets = pNewTargets;
m_dwSize = nNewSize; }
return TRUE; }
BOOL CEventBatch::AddEvent(IWbemClassObject *pObj, CSortedArray *pTrues) { BOOL bRet = FALSE;
if (EnsureAdditionalSize(1)) { if (SUCCEEDED(pObj->Clone(&m_ppObjs[m_nItems]))) { if(!TempSetTargets(m_pTargets + m_nItems, pTrues)) return FALSE;
m_nItems++;
bRet = TRUE; } }
return bRet; }
void CEventBatch::RemoveAll() { for (DWORD i = 0; i < m_nItems; i++) { m_ppObjs[i]->Release(); TempClearTargets(m_pTargets + i); }
m_nItems = 0; }
|