Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4807 lines
157 KiB

/*++
Copyright (C) 2000-2001 Microsoft Corporation
Module Name:
WmiFinalizer2
Abstract:
History:
paulall 27-Mar-2000 Created.
marioh 20-Oct-2000 Major updates completed
--*/
#include "precomp.h"
#include <stdio.h>
#include "wbemint.h"
#include "wbemcli.h"
#include "WmiFinalizer.h"
#include "coresvc.h"
#include "coreq.h"
#include <wbemcore.h>
#include <wmiarbitrator.h>
#include <autoptr.h>
#include <initguid.h>
#ifndef INITGUID
#define INITGUID
#endif
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Batching related registry data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define REGKEY_CIMOM "Software\\Microsoft\\Wbem\\CIMOM"
#define REGVALUE_BATCHSIZE "FinalizerBatchSize"
ULONG g_ulMaxBatchSize = 0;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Client callback related registry data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define REGVALUE_CLIENTCALLBACKTIMEOUT "ClientCallbackTimeout"
ULONG g_ulClientCallbackTimeout = 0;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Queue threshold related registry data
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define REGVALUE_QUEUETHRESHOLD "FinalizerQueueThreshold"
#define DEFAULT_QUEUETHRESHOLD 2
ULONG g_ulFinalizerQueueThreshold = 0;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Static declarations and initialization
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LONG s_Finalizer_ObjectCount = 0 ; // Global finalizer count
LONG s_FinalizerCallResult_ObjectCount = 0 ; // Global CallbackEesult count
LONG s_FinalizerEnum_ObjectCount = 0 ; // Global Enumerator count
LONG s_FinalizerEnumSink_ObjectCount = 0 ; // Global Enumerator sink count
LONG s_FinalizerInBoundSink_ObjectCount = 0 ; // Global InboundSink count
#define RET_FNLZR_ASSERT(msg, hres) return hres
#define FNLZR_ASSERT(msg, hres)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWMIFINALIZER
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::CWmiFinalizer()
//
// Peforms initialization of the finalizer.
//
// Exceptions thrown:
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CWmiFinalizer::CWmiFinalizer(CCoreServices *pSrvs)
: m_lRefCount(0),
m_lInternalRefCount(0),
m_phTask(NULL),
m_pArbitrator(NULL),
m_pDestSink(NULL),
m_uForwardingType(forwarding_type_none),
m_hresFinalResult(-1),
m_bRestartable(false),
m_uCurObjectPosition(0),
m_bSetStatusCalled(false),
m_bSetStatusConsumed(false),
m_ulQueueSize (0),
m_bCancelledCall (FALSE),
m_bNaughtyClient (FALSE),
m_ulStatus (WMI_FNLZR_STATE_NO_INPUT),
m_hCancelEvent (NULL),
m_hStatus (NoError),
m_ulOperationType (0),
m_ulSemisyncWakeupCall (0),
m_ulAsyncDeliveryCount (0),
m_apAsyncDeliveryBuffer (NULL),
m_lCurrentlyDelivering (FALSE),
m_lCurrentlyCancelling (FALSE),
m_enumBatchStatus (FinalizerBatch_NoError),
m_bSetStatusEnqueued ( FALSE ),
m_bSetStatusWithError ( FALSE ),
m_lMemoryConsumption ( 0 ),
m_bTaskInitialized ( FALSE ) ,
m_bClonedFinalizer ( FALSE ) ,
m_hWaitForSetStatus ( NULL ) ,
m_bSetStatusDelivered ( FALSE ),
m_LineCancelCall(0)
{
// validate CoreServices pointer
if (NULL == pSrvs) throw CX_MemoryException();
// Create m_hResultReceived handle
HANDLE hTmpResRecved = CreateEvent(NULL, TRUE, FALSE, NULL);
if ( NULL == hTmpResRecved ) throw CX_MemoryException();
OnDeleteIf<HANDLE,BOOL(*)(HANDLE),CloseHandle> cmResRecved(hTmpResRecved );
// Create m_hCancelEvent handle
HANDLE hTmpCancelEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == hTmpCancelEvent) throw CX_MemoryException();
OnDeleteIf<HANDLE,BOOL(*)(HANDLE),CloseHandle> cmCancelEvent (hTmpCancelEvent);
// Create new callresult
m_pCallResult = new CWmiFinalizerCallResult(this);
if (NULL == m_pCallResult) throw CX_MemoryException();
m_pCallResult->InternalAddRef();
cmResRecved.dismiss();
m_hResultReceived = hTmpResRecved;
cmCancelEvent.dismiss();
m_hCancelEvent = hTmpCancelEvent;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get arbitrator
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
m_pArbitrator = CWmiArbitrator::GetRefedArbitrator();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check what the batch size is supposed to be through registry.
// If not found, use default size defined in DEFAULT_BATCH_TRANSMIT_BYTES
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( !g_ulMaxBatchSize )
{
g_ulMaxBatchSize = DEFAULT_BATCH_TRANSMIT_BYTES;
Registry batchSize (HKEY_LOCAL_MACHINE, KEY_QUERY_VALUE, TEXT(REGKEY_CIMOM));
if ( batchSize.GetLastError() == ERROR_SUCCESS )
{
DWORD dwTmp;
batchSize.GetDWORD ( TEXT(REGVALUE_BATCHSIZE), &dwTmp );
if ( batchSize.GetLastError() == ERROR_SUCCESS )
g_ulMaxBatchSize = (LONG) dwTmp;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check what the timeout for client callbacks is supposed to be through registry.
// If not found, use default size defined in ABANDON_PROXY_THRESHOLD
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( !g_ulClientCallbackTimeout )
{
g_ulClientCallbackTimeout = ABANDON_PROXY_THRESHOLD;
Registry batchSize (HKEY_LOCAL_MACHINE, KEY_QUERY_VALUE, TEXT(REGKEY_CIMOM));
if ( batchSize.GetLastError() == ERROR_SUCCESS )
{
DWORD dwTmp;
batchSize.GetDWORD ( TEXT(REGVALUE_CLIENTCALLBACKTIMEOUT), &dwTmp );
if ( batchSize.GetLastError() == ERROR_SUCCESS )
g_ulClientCallbackTimeout = (LONG) dwTmp;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check what the timeout for client callbacks is supposed to be through registry.
// If not found, use default size defined in ABANDON_PROXY_THRESHOLD
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( !g_ulFinalizerQueueThreshold )
{
g_ulFinalizerQueueThreshold = DEFAULT_QUEUETHRESHOLD;
Registry batchSize (HKEY_LOCAL_MACHINE, KEY_QUERY_VALUE, TEXT(REGKEY_CIMOM));
if ( batchSize.GetLastError() == ERROR_SUCCESS )
{
DWORD dwTmp;
batchSize.GetDWORD ( TEXT(REGVALUE_QUEUETHRESHOLD), &dwTmp );
if ( batchSize.GetLastError() == ERROR_SUCCESS )
g_ulFinalizerQueueThreshold = (LONG) dwTmp;
}
}
InterlockedIncrement ( & s_Finalizer_ObjectCount ) ;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::~CWmiFinalizer()
//
// Destructor. Decrements global finalizer object count
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CWmiFinalizer::~CWmiFinalizer()
{
InterlockedDecrement ( & s_Finalizer_ObjectCount ) ;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Unregister with arbitrator
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (m_pArbitrator)
{
m_pArbitrator->UnRegisterArbitratee (0, m_phTask, this);
}
if ( m_phTask )
{
m_phTask->Release ( );
m_phTask = NULL ;
}
if (m_pArbitrator)
{
m_pArbitrator->Release();
m_pArbitrator = NULL ;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::CallBackRelease ()
//
// Called when the external ref count (client ref count) goes to zero.
// Performs following clean up tasks
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CWmiFinalizer::CallBackRelease ()
{
{
CInCritSec cs(&m_cs);
// Release the arbitrator and all inbound sinks
for (LONG i = 0; i < m_objects.Size(); i++)
{
CWmiFinalizerObj *pObj = (CWmiFinalizerObj*)m_objects[i];
delete pObj;
}
m_objects.Empty ( ) ;
}
for (int i = 0; i < m_inboundSinks.Size(); i++)
{
((CWmiFinalizerInboundSink*)m_inboundSinks[i])->InternalRelease();
}
m_inboundSinks.Empty();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Release the destination sink
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ReleaseDestinationSink();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If the call hasnt been cancelled already, go ahead and
// do so now
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (!m_bCancelledCall)
CancelTaskInternal();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Close all handles
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_hResultReceived )
{
SetEvent ( m_hResultReceived ) ;
CloseHandle ( m_hResultReceived);
m_hResultReceived = NULL ;
}
if ( m_hCancelEvent )
{
SetEvent ( m_hCancelEvent );
CloseHandle ( m_hCancelEvent );
m_hCancelEvent = NULL ;
}
// Release callresult and enumerator
m_pCallResult->InternalRelease();
m_pCallResult = NULL ;
//
// Release all enumerators associated with this finalizer
//
{
CInCritSec cs ( &m_cs ) ; // SEC:REVIEWED 2002-03-22 : Assumes entry
for ( i = 0; i < m_enumerators.Size(); i++ )
{
((CWmiFinalizerEnumerator*)m_enumerators[i])->InternalRelease ( ) ;
}
m_enumerators.Empty ( ) ;
}
NotifyClientOfCancelledCall ( ) ;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::CancelTaskInternal()
//
// Calls the arbitrator and unregisters the task
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT CWmiFinalizer::CancelTaskInternal ( )
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
HRESULT hRes = WBEM_E_FAILED;
if (m_phTask && m_pArbitrator)
{
hRes = m_pArbitrator->UnregisterTask(m_phTask);
}
return hRes;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
//
// Std implementation of QI
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
STDMETHODIMP CWmiFinalizer::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
if (ppvObj == 0)
return ERROR_INVALID_PARAMETER;
// SEC:REVIEWED 2002-03-22 : Ideally, we should have EH around all
// derefs of ppvObj, in case the memory is invalid.
if (IID_IUnknown==riid )
{
*ppvObj = (_IWmiFinalizer*)this;
}
else if (IID__IWmiFinalizer == riid)
{
*ppvObj = (_IWmiFinalizer*)this;
}
else if (IID__IWmiArbitratee == riid)
{
*ppvObj = (_IWmiArbitratee*)this;
}
else if (IID_IWbemShutdown == riid)
{
*ppvObj = (IWbemShutdown*)this;
}
else
{
*ppvObj = 0;
return E_NOINTERFACE;
}
((IUnknown *)(* ppvObj))->AddRef(); // SEC:REVIEWED 2002-03-22 : Needs EH
return NOERROR;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::AddRef()
//
// Std implementation of AddRef.
// Also does internal addref
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ULONG CWmiFinalizer::AddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lRefCount);
if ( uNewCount == 1 )
{
InternalAddRef () ;
}
return uNewCount;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::Release()
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ULONG CWmiFinalizer::Release()
{
ULONG uNewCount = InterlockedDecrement(&m_lRefCount);
if (0 == uNewCount)
{
CallBackRelease () ;
InternalRelease () ;
}
return uNewCount;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CWmiFinalizer::InternalAddRef()
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ULONG CWmiFinalizer::InternalAddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lInternalRefCount);
return uNewCount;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ULONG CWmiFinalizer::InternalRelease()
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ULONG CWmiFinalizer::InternalRelease()
{
ULONG uNewCount = InterlockedDecrement(&m_lInternalRefCount);
if (0 == uNewCount)
{
delete this ;
}
return uNewCount;
}
/*
* =====================================================================================================
|
| HRESULT CWmiFinalizer::ReportMemoryUsage ( ULONG lFlags, LONG lDelta )
| ----------------------------------------------------------------------
|
| Common point to report memory consumption to the arbitrator.
|
| Uses m_phTask when calling arbitrator.
|
|
|
* =====================================================================================================
*/
HRESULT CWmiFinalizer::ReleaseDestinationSink ( )
{
HRESULT hRes = WBEM_S_NO_ERROR ;
{
CInCritSec lock(&m_destCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if (m_pDestSink)
{
m_pDestSink->Release(); // SEC:REVIEWED 2002-03-22 : Needs EH in case user sink is garbage
m_pDestSink = 0;
}
}
NotifyClientOfCancelledCall ( ) ;
return hRes ;
}
/*
* =====================================================================================================
|
| HRESULT CWmiFinalizer::ReportMemoryUsage ( ULONG lFlags, LONG lDelta )
| ----------------------------------------------------------------------
|
| Common point to report memory consumption to the arbitrator.
|
| Uses m_phTask when calling arbitrator.
|
|
|
* =====================================================================================================
*/
HRESULT CWmiFinalizer::ReportMemoryUsage ( ULONG lFlags, LONG lDelta )
{
HRESULT hRes = WBEM_S_NO_ERROR ;
if (m_pArbitrator)
hRes = m_pArbitrator->ReportMemoryUsage ( lFlags, lDelta, m_phTask ) ;
//
// Atomic update of MemoryConsumption
//
InterlockedExchangeAdd ( &m_lMemoryConsumption, lDelta ) ;
return hRes ;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// CWmiFinalizer::Configure
// ------------------------
//
// Allows decoupled & fast-track configuration with no thread switches.
// Also will be used to configure cache operations and the likes.
//
// Parameters
// ----------
// uConfigID - One of the values defined in WMI_FNLZR_CFG_TYPE
// pConfigVal - Additional information needed
// Return codes
// ------------
// WBEM_E_INVALID_OPERATION - try to do the same thing more than once, or
// trying to change something already set up
// WBEM_E_INVALID_PARAMETER - Configuration parameter we do not know about
// was passed in
// WBEM_NO_ERROR - Everything went well
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
STDMETHODIMP CWmiFinalizer::Configure(
/*[in]*/ ULONG uConfigID,
/*[in]*/ ULONG uValue
)
{
switch (uConfigID)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Do they want us to fast track?
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case WMI_FNLZR_FLAG_FAST_TRACK:
{
if (m_uForwardingType != forwarding_type_none)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::Configure called more than once!"), WBEM_E_INVALID_OPERATION);
m_uForwardingType = forwarding_type_fast;
break;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Do they want us to decouple?
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case WMI_FNLZR_FLAG_DECOUPLED:
{
if (m_uForwardingType != forwarding_type_none)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::Configure called more than once!"), WBEM_E_INVALID_OPERATION);
m_uForwardingType = forwarding_type_decoupled;
DWORD dwThreadId = 0;
break;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Do they want us to do anything else? If so, assert
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
default:
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::Configure - invalid parameter uConfigID"), WBEM_E_INVALID_PARAMETER);
}
return WBEM_NO_ERROR;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// CWmiFinalizer::SetTaskHandle
// ----------------------------
//
// Task handle has user-specific stuff. Finalizer just
// passes this through to _IWmiArbitrator::CheckTask. It should only ever
// be called once
//
// Parameters
// ----------
// phTask - Pointer to the task handle
// Return codes
// ------------
// WBEM_E_INVALID_OPERATION - try to do the same call more than once
// WBEM_E_INVALID_PARAMETER - Passed in parameter is invalid
// WBEM_NO_ERROR - Everything went well
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
STDMETHODIMP CWmiFinalizer::SetTaskHandle(
_IWmiCoreHandle *phTask
)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Parameter validation
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (m_phTask != NULL)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetTaskHandle - already have m_phTask"), WBEM_E_INVALID_OPERATION);
if (phTask == NULL)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetTaskHandle - phTask == NULL"), WBEM_E_INVALID_PARAMETER);
m_bTaskInitialized = TRUE ;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Assign the task and AddRef it
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
m_phTask = phTask;
m_phTask->AddRef();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Register the finalizer with the arbitrator
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if (m_pArbitrator)
{
m_pArbitrator->RegisterArbitratee(0, m_phTask, this);
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// From the task, we can now see exactly what type of operation we are doing.
// Get the operation type (SYNC/SEMISYNC/ASYNC) to avoid having to get it every time
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CWmiTask *pTsk = (CWmiTask *) m_phTask;
ULONG ulTaskType = pTsk->GetTaskType();
if ( (ulTaskType & WMICORE_TASK_TYPE_SYNC) )
{
m_ulOperationType = Operation_Type_Sync;
}
else if ( (ulTaskType & WMICORE_TASK_TYPE_SEMISYNC) )
{
m_ulOperationType = Operation_Type_Semisync;
}
else if ( (ulTaskType & WMICORE_TASK_TYPE_ASYNC) )
{
m_ulOperationType = Operation_Type_Async;
}
else
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetTaskHandle - Invalid operation type"), WBEM_E_FAILED );
return WBEM_NO_ERROR;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// CWmiFinalizer::SetDestinationSink
// ---------------------------------
//
// For async operations, therefore if the forwarding type is not set to
// decoupled, this will fail. If there are any items outstanding,
// this will also trigger them to be started
//
// Parameters
// ----------
// uFlags - unused
//
// pSink - pointer to the created destination sink
//
// Return codes
// ------------
// WBEM_E_INVALID_OPERATION - try to do the same call more than once
// WBEM_E_INVALID_PARAMETER - Passed in parameter is invalid
// WBEM_NO_ERROR - Everything went well
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
STDMETHODIMP CWmiFinalizer::SetDestinationSink(
/*[in]*/ ULONG uFlags,
/*[in]*/ REFIID riid,
/*[in], iid_is(riid)]*/ LPVOID pVoid
)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Parameter validation
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (m_pDestSink != NULL)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetDestinationSink - m_pDestSink != NULL"), WBEM_E_INVALID_OPERATION);
if ((pVoid == NULL) || (uFlags != 0))
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetDestinationSink - ((pSink == NULL) || (uFlags != 0))"), WBEM_E_INVALID_PARAMETER);
if (m_uForwardingType == forwarding_type_none)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetDestinationSink - m_uForwardingType == forwarding_type_none"), WBEM_E_INVALID_OPERATION);
if ((riid != IID_IWbemObjectSink) )
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetDestinationSink - iid must be IID_IWbemObjectSink"), WBEM_E_INVALID_PARAMETER);
HRESULT hr;
IWbemObjectSink * pSink = (IWbemObjectSink *)pVoid;
IWbemObjectSink * pSinkToStore = NULL;
m_iidDestSink = IID_IWbemObjectSink;
pSinkToStore = pSink;
// Set the destination sink, AddRef it and set the impersonation level
// to identity
{
CInCritSec lock(&m_destCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
m_pDestSink = pSinkToStore;
m_pDestSink->AddRef(); // SEC:REVIEWED 2002-03-22 : Needs EH in case sink is garbage
SetSinkToIdentity (m_pDestSink);
}
return WBEM_NO_ERROR;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The callback called during final Release(); Set() is called with the
// task handle, followed by SetStatus()
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
STDMETHODIMP CWmiFinalizer::SetSelfDestructCallback(
/*[in]*/ ULONG uFlags,
/*[in]*/ IWbemObjectSink *pSink
)
{
return E_NOTIMPL;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// STDMETHODIMP CWmiFinalizer::GetStatus(
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
STDMETHODIMP CWmiFinalizer::GetStatus(
ULONG *pFlags
)
{
*pFlags = m_ulStatus;
return WBEM_NO_ERROR;
}
//***************************************************************************
//
// CWmiFinalizer::NewInboundSink
// -----------------------------
//
// Returns a sink to the caller. This sink is used to indicate result sets
// back to the client.
//
// Parameters
// ----------
// uFlags - Additional flags. Currently 0 is only valid value.
// pSink - Pointer to variable which will get the returned inbound sink.
// It is this sink that allows the caller to send result sets.
//
// Return codes
// ------------
// WBEM_E_OUT_OF_MEMORY - Failed to create the finaliser sink because of an
// out of memory situation
// WBEM_E_INVALID_PARAMETER - Invalid parameters passed to method
// WBEM_NO_ERROR - Everything completed successfully
//***************************************************************************
STDMETHODIMP CWmiFinalizer::NewInboundSink(
/*[in]*/ ULONG uFlags,
/*[out]*/ IWbemObjectSink **pSink
)
{
if ((pSink == NULL) || (uFlags != 0))
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::NewInboundSink - ((pSink == NULL) || (uFlags != 0))!"), WBEM_E_INVALID_PARAMETER);
if (m_inboundSinks.Size())
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::NewInboundSink - Multiple inbound sinks not yet implemented!!"), E_NOTIMPL);
CWmiFinalizerInboundSink *pNewSink = new CWmiFinalizerInboundSink(this);
if (pNewSink == NULL)
return WBEM_E_OUT_OF_MEMORY;
pNewSink->AddRef(); // Required to return a positive ref count on a new object // SEC:REVIEWED 2002-03-22 : OK
CInCritSec autoLock(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
int nRet = m_inboundSinks.Add(pNewSink);
if (nRet != CFlexArray::no_error)
{
pNewSink->Release();
return WBEM_E_OUT_OF_MEMORY;
}
else
{
pNewSink->InternalAddRef();
}
*pSink = pNewSink; // SEC:REVIEWED 2002-03-22 : Should be in EH if case memory is not valid
return WBEM_NO_ERROR;
}
//***************************************************************************
//
// Allows merging another Finalizer, _IWmiCache, etc.
// For sorting, we will create a sorted _IWmiCache and merge it in later when
// the sort is completed.
//
//***************************************************************************
STDMETHODIMP CWmiFinalizer::Merge(
/*[in]*/ ULONG uFlags,
/*[in]*/ REFIID riid,
/*[in]*/ LPVOID pObj
)
{
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::Merge - Not implemented!"), E_NOTIMPL);
}
// For setting, getting objects
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizer::SetResultObject(
/*[in]*/ ULONG uFlags,
/*[in]*/ REFIID riid,
/*[in]*/ LPVOID pObj
)
{
//No one is calling this! All objects are getting in through a call to Indicate,
//or Set, which are both just forwards from the InboundSink we pass out.
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::Merge - Not implemented!"), E_NOTIMPL);
}
//***************************************************************************
//
// Support _IWmiObject, IWbemClassObject, etc.
// IEnumWbemClassObject
// _IWmiCache
//
//***************************************************************************
STDMETHODIMP CWmiFinalizer::GetResultObject(
/*[in]*/ ULONG uFlags,
/*[in]*/ REFIID riid,
/*[out, iid_is(riid)]*/ LPVOID *ppObj
)
{
// uFlags can be non-zero iff the requested interface is an enumerator
if (uFlags != 0 && riid != IID_IEnumWbemClassObject)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::GetResultObject - uFlags != 0, non enum interface!"), WBEM_E_INVALID_PARAMETER);
if (riid == IID_IEnumWbemClassObject)
{
//If forward-only is set we should not let the result set be restartable.
if (!(uFlags & WBEM_FLAG_FORWARD_ONLY))
m_bRestartable = true;
//m_uDeliveryType = delivery_type_pull;
CWmiFinalizerEnumerator* pEnum = NULL ;
try
{
//
// I'm using the uFlags as a means of passing the current object position
//
pEnum = new CWmiFinalizerEnumerator(this);
}
catch (...) // status_no_memory
{
ExceptionCounter c;
}
if (pEnum == NULL)
return WBEM_E_OUT_OF_MEMORY;
else
pEnum->InternalAddRef();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure nasty client does not crash us
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
*ppObj = pEnum;
}
catch (...) // ppObj is an untrusted param
{
ExceptionCounter c;
pEnum->InternalRelease();
return WBEM_E_INVALID_PARAMETER;
}
{
CInCritSec lock( &m_cs ) ; // SEC:REVIEWED 2002-03-22 : Assumes entry
//
// Lets add the enumerator to the list of enumerators
// associated with this finalizer.
//
int nRet = m_enumerators.Add ( pEnum ) ;
if ( nRet != CFlexArray::no_error )
{
pEnum->InternalRelease ( ) ;
return WBEM_E_OUT_OF_MEMORY;
}
}
pEnum->AddRef();
return WBEM_NO_ERROR;
}
//Get the next object we have cached.
if ((riid == IID_IWbemClassObject) || (riid == IID__IWmiObject))
{
if (m_pDestSink != NULL)
{
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::GetResultObject - Cannot get an object when there is a destination sink!"), WBEM_E_INVALID_OPERATION);
}
if (m_bSetStatusConsumed)
return WBEM_E_NOT_FOUND;
CWmiFinalizerObj *pFinalizerObj = NULL;
bool bFinished = false;
HRESULT hRes = WBEM_E_NOT_FOUND;
while (!bFinished)
{
hRes = GetNextObject(&pFinalizerObj);
if (FAILED(hRes))
return hRes;
else if (hRes == WBEM_S_FALSE)
return WBEM_E_NOT_FOUND;
if (pFinalizerObj->m_objectType == CWmiFinalizerObj::object)
{
if (ppObj)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure nasty client does not crash us
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
*ppObj = pFinalizerObj->m_pObj;
}
catch (...) // untrusted param
{
ExceptionCounter c;
return WBEM_E_INVALID_PARAMETER;
}
if (pFinalizerObj->m_pObj)
pFinalizerObj->m_pObj->AddRef();
}
bFinished = true;
}
else if ((pFinalizerObj->m_objectType == CWmiFinalizerObj::status) && (pFinalizerObj->m_lFlags == WBEM_STATUS_COMPLETE))
{
m_bSetStatusConsumed = true;
hRes = WBEM_E_NOT_FOUND;
bFinished = true;
}
else if (pFinalizerObj->m_objectType == CWmiFinalizerObj::status)
{
//This is a non-completion status message! We most certainly have not finished yet!
}
delete pFinalizerObj;
}
return hRes;
}
if ((riid == IID_IWbemCallResult) )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure nasty client does not crash us
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
m_pCallResult->AddRef();
*ppObj = m_pCallResult;
}
catch (...) // untrusted param
{
ExceptionCounter c;
m_pCallResult->Release ();
return WBEM_E_INVALID_PARAMETER;
}
return WBEM_S_NO_ERROR;
}
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::GetResultObject - Unknown object IID requested!"), WBEM_E_INVALID_PARAMETER);
}
// For status-only operations
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizer::SetOperationResult(
/*[in]*/ ULONG uFlags,
/*[in]*/ HRESULT hRes
)
{
if (uFlags != 0)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetOperationResult - uFlags != 0!"), WBEM_E_INVALID_PARAMETER);
if ( m_hresFinalResult != -1 )
{
if ( hRes != WBEM_E_CALL_CANCELLED )
{
return WBEM_S_NO_ERROR ;
}
}
if ( hRes == WBEM_E_CALL_CANCELLED_CLIENT )
{
m_hresFinalResult = hRes = WBEM_E_CALL_CANCELLED ;
}
else if ( hRes != WBEM_E_CALL_CANCELLED )
{
m_hresFinalResult = hRes ;
}
HRESULT hResCancel = WBEM_NO_ERROR ;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Special case for cancellations. Iff its an async operation. Otherwise,
// we might mess up for sync/semi sync
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( ( hRes == WBEM_E_CALL_CANCELLED ) && ( m_ulOperationType == Operation_Type_Async ) )
{
hResCancel = CancelCall(__LINE__);
}
SetEvent(m_hResultReceived);
return hResCancel ;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizer::GetOperationResult(
/*[in]*/ ULONG uFlags,
/*[in]*/ ULONG uTimeout,
/*[out]*/ HRESULT *phRes
)
{
if (uFlags != 0)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::GetOperationResult - uFlags != 0!"), WBEM_E_INVALID_PARAMETER);
HRESULT hr = WaitForCompletion(uTimeout);
if (hr == WBEM_S_NO_ERROR)
{
*phRes = m_hresFinalResult; // SEC:REVIEWED 2002-03-22 : Needs EH
if ( FAILED ( m_hresFinalResult ) )
{
m_pCallResult->SetErrorInfo ( ); // SEC:REVIEWED 2002-03-22 : Needs EH
}
CancelTaskInternal();
m_hStatus = NoError;
}
return hr;
}
//***************************************************************************
// STDMETHODIMP CWmiFinalizer::CancelTask(
//***************************************************************************
STDMETHODIMP CWmiFinalizer::CancelTask(
/*[in]*/ ULONG uFlags
)
{
if (uFlags != 0)
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::CancelTask - uFlags != 0!"), WBEM_E_INVALID_PARAMETER);
return CancelTaskInternal ( );
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::WaitForCompletion(ULONG uTimeout)
{
DWORD dwRet = CCoreQueue :: QueueWaitForSingleObject(m_hResultReceived, uTimeout);
if (dwRet == WAIT_OBJECT_0)
{
return WBEM_S_NO_ERROR;
}
else if ((dwRet == WAIT_FAILED) ||
(dwRet == WAIT_ABANDONED))
{
return WBEM_E_FAILED;
}
else
{
return WBEM_S_TIMEDOUT;
}
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::Reset(
)
{
if (m_bRestartable)
{
/*m_uCurObjectPosition = 0;
m_bSetStatusConsumed = false;*/
return WBEM_NO_ERROR;
}
else
return WBEM_E_INVALID_OPERATION;
}
//***************************************************************************
//
//***************************************************************************
IWbemObjectSink* CWmiFinalizer::ReturnProtectedDestinationSink ( )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Do we have a valid object sink?
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IWbemObjectSink* pTmp = NULL;
{
CInCritSec lock(&m_destCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_pDestSink==NULL )
{
return NULL;
}
else
{
pTmp = m_pDestSink;
pTmp->AddRef(); // SEC:REVIEWED 2002-03-22 : Needs EH in case sink is garbage
}
}
return pTmp;
}
//***************************************************************************
//
//***************************************************************************
DWORD WINAPI CWmiFinalizer::ThreadBootstrap( PVOID pParam )
{
// char buff[100];
// sprintf(buff, "thread this pointer = 0x%p\n", pParam);
// OutputDebugString(buff);
return ((CWmiFinalizer*)pParam)->AsyncDeliveryProcessor();
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::BootstrapDeliveryThread ( )
{
BOOL bRes;
HRESULT hRes = WBEM_S_NO_ERROR;
AddRef(); // Need to AddRef Finalizer for the delivery thread
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Native Win2k thread dispatching
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bRes = QueueUserWorkItem ( ThreadBootstrap, this, WT_EXECUTEDEFAULT );
if ( !bRes )
{
Release ();
hRes = WBEM_E_FAILED;
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizer::AsyncDeliveryProcessor()
{
HRESULT hRes = WBEM_S_NO_ERROR;
BOOL bKeepDelivering = TRUE;
m_enumBatchStatus = FinalizerBatch_NoError;
RevertToSelf ( ); // SEC:REVIEWED 2002-03-22 : Needs check
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// First we tell the arbitrator about the delivery thread
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if (m_pArbitrator)
{
hRes = m_pArbitrator->RegisterThreadForTask(m_phTask);
if (hRes == WBEM_E_QUOTA_VIOLATION)
{
//TODO: WHAT HAPPENS HERE?
}
}
}
while ( bKeepDelivering )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// First off, have we been cancelled?
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_bCancelledCall )
{
DeliverSingleObjFromQueue ( );
bKeepDelivering = FALSE;
continue;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Next, we build the transmit buffer
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hRes = BuildTransmitBuffer ( );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BuildTransmitBuffer will return WBEM_S_FALSE if the batch immediately hit a
// status message.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( hRes != WBEM_E_FAILED )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Next, deliver the batch of objects
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DeliverBatch ( );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we have a status message to deliver do so now
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_enumBatchStatus == FinalizerBatch_StatusMsg )
{
DeliverSingleObjFromQueue ( );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we have a status complete message we should keep building the batch and
// delivering until done
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_bSetStatusEnqueued && m_objects.Size() )
continue;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// We could have another batch to deliver by now. Check
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if ( m_ulQueueSize < g_ulMaxBatchSize )
bKeepDelivering = FALSE;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure we're properly synchronized with the inbound threads
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CInCritSec cs(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
{
if ( !m_bSetStatusEnqueued )
{
bKeepDelivering = FALSE;
m_lCurrentlyDelivering = FALSE;
}
else
{
bKeepDelivering = TRUE;
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tell the arbitrator that the thread is done
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if (m_pArbitrator)
{
m_pArbitrator->UnregisterThreadForTask(m_phTask); // Since thread is going away, tell arbitrator about this
}
}
Release();
return 0;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::GetNextObject(CWmiFinalizerObj **ppObj)
{
if (m_uCurObjectPosition >= (ULONG)m_objects.Size())
return WBEM_S_FALSE;
CInCritSec cs(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
CWmiFinalizerObj *pStorageObject = (CWmiFinalizerObj*)m_objects[m_uCurObjectPosition];
if (m_bRestartable)
{
//We have to hold on to results, so increment cursor position...
m_uCurObjectPosition++;
*ppObj = new CWmiFinalizerObj(*pStorageObject); // SEC:REVIEWED 2002-03-22 : Needs EH and NULL test
if (*ppObj == NULL)
return WBEM_E_OUT_OF_MEMORY;
//ReportMemoryUsage ( 0, (*ppObj)->m_uSize ) ;
}
else
{
//We are not restartable, therefore we need to release everything...
m_objects.RemoveAt(0);
*ppObj = pStorageObject; // SEC:REVIEWED 2002-03-22 : Needs EH and NULL test
//ADDBACK: ReportMemoryUsage ( 0, -((*ppObj)->m_uSize) ) ;
// printf("Returning object 0x%p from object list\n", pStorageObject);
}
return WBEM_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::UnregisterInboundSink(CWmiFinalizerInboundSink *pSink)
{
// Use m_cs lock for this
CInCritSec lock(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
for (int i = 0; i != m_inboundSinks.Size(); i++)
{
if (m_inboundSinks[i] == pSink)
{
pSink->InternalRelease () ; // SEC:REVIEWED 2002-03-22 : Could use an EH for safety
m_inboundSinks.RemoveAt(i);
if (m_inboundSinks.Size() == 0)
TriggerShutdown();
return WBEM_NO_ERROR;
}
}
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::UnregisterInboundSink - Unregistering Inbound Sink that we could not find!"), WBEM_E_NOT_FOUND);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::Indicate(
/*[in]*/ long lObjectCount,
/*[in, size_is(lObjectCount)]*/
IWbemClassObject** apObjArray
)
{
HRESULT hRes = WBEM_S_NO_ERROR;
if ( m_bCancelledCall )
{
return WBEM_E_CALL_CANCELLED;
}
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_bSetStatusCalled )
{
return WBEM_E_INVALID_OPERATION;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// First check the array for NULL objects. Return INVALID_OBJECT if
// array contains a NULL object
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (long x = 0; x != lObjectCount; x++)
{
if ( apObjArray[x] == NULL ) // SEC:REVIEWED 2002-03-22 : Needs EH
return WBEM_E_INVALID_OBJECT;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Are we fast tracking and async request?
// ESS brutally tells us to deliver on the
// same thread and do no batching
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( (m_uForwardingType == forwarding_type_fast) && (m_ulOperationType == Operation_Type_Async))
{
IWbemObjectSink* pTmp = ReturnProtectedDestinationSink ( );
if ( !pTmp )
{
return WBEM_E_FAILED;
}
CReleaseMe myReleaseMe(pTmp);
hRes = DoIndicate ( pTmp, lObjectCount, apObjArray ); // SEC:REVIEWED 2002-03-22 : Needs EH in case <apObjArray> is garbage
// Client can also tell us to cancel a call by returning WBEM_E_CALL_CANCELLED from Indicate
// We also want to cancel the call if the client is taking way too long to return
if ( FAILED (hRes) || m_bCancelledCall == TRUE || m_bNaughtyClient == TRUE )
{
if ( hRes == WBEM_E_CALL_CANCELLED || m_bCancelledCall )
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, 0 );
}
else
{
DoSetStatusCancel ( pTmp, hRes );
}
hRes = WBEM_E_CALL_CANCELLED;
myReleaseMe.release ( ) ;
ReleaseDestinationSink ( ) ;
CancelCall(__LINE__);
}
}
else
{
for (long lIndex = 0; lIndex != lObjectCount; lIndex++)
{
if ( apObjArray[lIndex] ) // SEC:REVIEWED 2002-03-22 : Needs EH
{
CWmiFinalizerObj *pFinalizerObj = new CWmiFinalizerObj(apObjArray[lIndex], this); // SEC:REVIEWED 2002-03-22 : Needs EH
if (pFinalizerObj == NULL) return WBEM_E_OUT_OF_MEMORY;
HRESULT hr = QueueOperation(pFinalizerObj);
if (FAILED(hr)) return hr; // queue will always destroy pFinalizerObj
}
}
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::Set(
/*[in]*/ long lFlags,
/*[in]*/ REFIID riid,
/*[in, iid_is(riid)]*/ void *pComObject
)
{
CWmiFinalizerObj *pFinalizerObj = new CWmiFinalizerObj(lFlags, riid, pComObject); // SEC:REVIEWED 2002-03-22 : Needs EH
if (pFinalizerObj == NULL) return WBEM_E_OUT_OF_MEMORY;
return QueueOperation(pFinalizerObj);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::SetStatus(
/*[in]*/ long lFlags,
/*[in]*/ HRESULT hResult,
/*[in]*/ BSTR strParam,
/*[in]*/ IWbemClassObject* pObjParam
)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If the operation has been cancelled, we should not accept another call
// WBEM_E_CALL_CANCELLED
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_bCancelledCall )
{
return WBEM_E_CALL_CANCELLED;
}
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_bSetStatusCalled && ( lFlags == WBEM_STATUS_COMPLETE ) )
{
return WBEM_E_INVALID_OPERATION;
}
else if ( lFlags == WBEM_STATUS_COMPLETE )
{
m_bSetStatusCalled = true ;
}
}
//If this is a final call, we need to record it.
if (lFlags == WBEM_STATUS_COMPLETE )
{
m_pCallResult->SetStatus(lFlags, hResult, strParam, pObjParam);
}
// Special case for cancellations
if ( hResult == WBEM_E_CALL_CANCELLED )
{
HRESULT hr = CancelCall(__LINE__);
SetEvent(m_hResultReceived);
return hr;
}
HRESULT ourhres = WBEM_E_FAILED;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Once again, we have to special case ESS
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( (m_uForwardingType == forwarding_type_fast) &&
(m_ulOperationType == Operation_Type_Async) )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Do we have a valid object sink?
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IWbemObjectSink* pTmp = ReturnProtectedDestinationSink();
CReleaseMe myReleaseMe(pTmp);
if ( pTmp )
{
ourhres = DoSetStatus ( pTmp, lFlags, hResult, strParam, pObjParam );
if (lFlags == WBEM_STATUS_COMPLETE ||
FAILED ( ourhres ) ||
m_bCancelledCall == TRUE ||
m_bNaughtyClient == TRUE )
{
NotifyAllEnumeratorsOfCompletion ( ) ;
SetOperationResult(0, hResult);
{
CInCritSec lock(&m_destCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_pDestSink )
{
ReleaseDestinationSink ( ) ;
m_bSetStatusConsumed = true;
UpdateStatus ( WMI_FNLZR_STATE_CLIENT_COMPLETE );
}
}
CancelTaskInternal ( );
if ( FAILED ( ourhres ) || m_bCancelledCall == TRUE || m_bNaughtyClient == TRUE )
{
ourhres = WBEM_E_CALL_CANCELLED ;
}
}
}
}
else
{
//Send the request to the user...
// ObjectType::status
CWmiFinalizerObj *pObj = new CWmiFinalizerObj(lFlags, hResult, strParam, pObjParam); // SEC:REVIEWED 2002-03-22 : Needs EH
if (pObj == NULL)
{
IWbemObjectSink* pTmp = ReturnProtectedDestinationSink();
CReleaseMe myReleaseMe(pTmp);
if ( pTmp )
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 ) ;
}
SetOperationResult(0,WBEM_E_OUT_OF_MEMORY);
m_hStatus = QueueFailure;
NotifyAllEnumeratorsOfCompletion();
return WBEM_E_OUT_OF_MEMORY;
}
ourhres = QueueOperation(pObj);
if (lFlags == WBEM_STATUS_COMPLETE)
{
SetOperationResult(0, hResult);
//QueueFailure is set internally in the QueueOperation
NotifyAllEnumeratorsOfCompletion ( ) ;
//
// Lock the task
//
CWmiTask* pTask = NULL ;
{
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_phTask )
{
pTask = (CWmiTask*) m_phTask ;
pTask->AddRef ( ) ;
}
}
CReleaseMe _r ( pTask ) ;
if ( pTask )
{
pTask->SetTaskResult ( hResult ) ;
}
((CWmiArbitrator*) m_pArbitrator)->UnregisterTaskForEntryThrottling ( (CWmiTask*) m_phTask ) ;
}
}
return ourhres;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::QueueOperation(CWmiFinalizerObj *pObj)
{
LONG lDelta = 0;
HRESULT hRes = WBEM_S_NO_ERROR;
CCheckedInCritSec cs ( &m_cs ) ; // SEC:REVIEWED 2002-03-22 : Assumes entry
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update total object size
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (pObj->m_objectType == CWmiFinalizerObj::object)
{
CWbemObject* pObjTmp = (CWbemObject*) pObj -> m_pObj;
m_ulQueueSize += pObjTmp -> GetBlockLength();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we get a WBEM_E_CALL_CANCELLED status message, prioritize
// the handling of this. Needed for fast shutdown.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( (pObj->m_objectType == CWmiFinalizerObj::status) && FAILED (pObj->m_hRes) )
{
m_bSetStatusWithError = TRUE ;
if (CFlexArray::no_error != m_objects.InsertAt ( 0, pObj ))
{
delete pObj;
m_hStatus = QueueFailure;
return WBEM_E_OUT_OF_MEMORY;
}
}
else
{
// Normal Add object to queue
if (CFlexArray::no_error != m_objects.Add(pObj))
{
delete pObj;
m_hStatus = QueueFailure;
return WBEM_E_OUT_OF_MEMORY;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// First we check with the arbitrator what it tells us about
// current limits. Make sure we call ReportMemoryUsage since
// we're only interested in what it would potentially have done.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT hArb = WBEM_S_ARB_NOTHROTTLING;
lDelta = pObj->m_uSize;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Are we decoupled, if so we need to analyze the current batch
// and make decisions on delivery. Need to once again special case ESS.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_uForwardingType == forwarding_type_decoupled ||
( m_uForwardingType == forwarding_type_fast &&
m_ulOperationType == Operation_Type_Async ) )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// What did the arbitrator tell us about our situation?
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( pObj->m_hArb != WBEM_S_ARB_NOTHROTTLING )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Arbitrator told us that we either were about to be
// cancelled or throttled. Flush our delivery buffers
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_lCurrentlyDelivering == FALSE || m_lCurrentlyCancelling == TRUE )
{
m_lCurrentlyDelivering = TRUE;
BootstrapDeliveryThread( ); // Kick of the delivery thread since we're decoupled
}
cs.Leave ( ) ;
hArb = m_pArbitrator->Throttle ( 0, m_phTask );
if ( hArb == WBEM_E_ARB_CANCEL )
{
CancelCall( __LINE__);
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we are decoupled and get a Status message we should deliver
// the batch and set the status
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if ( (pObj->m_objectType == CWmiFinalizerObj::status) )
{
if ( pObj->m_lFlags == WBEM_STATUS_COMPLETE )
{
m_bSetStatusEnqueued = TRUE;
}
if ( m_lCurrentlyDelivering == FALSE || m_lCurrentlyCancelling == TRUE )
{
m_lCurrentlyDelivering = TRUE;
BootstrapDeliveryThread ( ); // Kick of the delivery thread since we're decoupled
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Delivery needs to be decoupled
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if ( (m_ulQueueSize > g_ulMaxBatchSize) )
{
if ( m_lCurrentlyDelivering == FALSE )
{
m_lCurrentlyDelivering = TRUE;
BootstrapDeliveryThread ( ); // Kick of the delivery thread since we're decoupled
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Otherwise, we wake up any potential clients waiting in
// PullObjects
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if ( m_uForwardingType == forwarding_type_fast )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// We dont want to wake up the client unless we have the
// number of objects he/she requested OR a setstatus has
// come through [CWmiFinalizer::SetStatus]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( (pObj->m_objectType == CWmiFinalizerObj::object) )
{
for ( int i = 0; i < m_enumerators.Size ( ); i++ )
{
CWmiFinalizerEnumerator* pEnum = (CWmiFinalizerEnumerator*) m_enumerators[i] ;
if ( ( pEnum->m_ulSemisyncWakeupCall != 0 ) && ( m_objects.Size() >= ( pEnum->m_ulSemisyncWakeupCall + pEnum->m_uCurObjectPosition ) ) )
{
SetEvent ( pEnum->m_hWaitOnResultSet );
pEnum->m_ulSemisyncWakeupCall = 0;
}
}
}
else if ( (pObj->m_objectType == CWmiFinalizerObj::status) )
{
NotifyAllEnumeratorsOfCompletion ( ) ;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now, lets throttle this thread since we have no control
// of outbound flow
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cs.Leave ( ) ;
HRESULT hArb = m_pArbitrator->Throttle ( 0, m_phTask );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If the arbitrator returned CANCEL, we operation has been
// cancelled and we need to stop:
// 1. Threads potentially waiting in the enumerator
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( hArb == WBEM_E_ARB_CANCEL )
{
cs.Leave ( ) ;
CancelTaskInternal ( );
cs.Enter ( ) ;
m_hStatus = QuotaViolation;
NotifyAllEnumeratorsOfCompletion ( ) ;
hRes = WBEM_E_QUOTA_VIOLATION;
}
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::TriggerShutdown()
{
if (m_uForwardingType == forwarding_type_decoupled)
{
//We need to queue up a shutdown request to the thread...
CWmiFinalizerObj *pObj = new CWmiFinalizerObj(CWmiFinalizerObj::shutdown); // SEC:REVIEWED 2002-03-22 : Needs EH
if (pObj == NULL) return WBEM_E_OUT_OF_MEMORY;
return QueueOperation(pObj);
}
else
ShutdownFinalizer();
return WBEM_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::ShutdownFinalizer()
{
return WBEM_NO_ERROR;
}
//****************************************************************************
// BuildTransmitBuffer ( )
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Works in two phases.
//
// 1. Quickly scans the object queue to get a count of the number of objects
// 2. Actually dequeueus the objects and builds the buffer
//
//****************************************************************************
HRESULT CWmiFinalizer::BuildTransmitBuffer ( )
{
HRESULT hRes = WBEM_NO_ERROR;
ULONG nBatchSize = 0;
ULONG nBatchBytes = 0;
ULONG nTempAdd = 0;
m_ulAsyncDeliveryCount = 0;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Lock the object queue while building the transmit buffer
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CInCritSec cs(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// PHASE 1
// -------
// Quickly scan through the object queue to get an object count
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool bBuildingBuffer = true;
while ( bBuildingBuffer && nTempAdd < m_objects.Size() )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// First, we peek at the object. Dont want to dequeue anything that is not
// deliverable in this batch
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CWmiFinalizerObj *pFinObj;
pFinObj = (CWmiFinalizerObj*) m_objects[m_uCurObjectPosition + nTempAdd];
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we get a NULL pointer back we should stop the batch count
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( pFinObj == NULL )
{
bBuildingBuffer = false;
m_enumBatchStatus = FinalizerBatch_NoError;
break;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Anything else BUT an object will break the batch count
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( pFinObj->m_objectType != CWmiFinalizerObj::object )
{
m_enumBatchStatus = FinalizerBatch_StatusMsg;
break;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we have a NULL IWbemClassObject we should stop the batch count.
// Actaully we should yell very loudly!
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CWbemObject* pObj = (CWbemObject*) pFinObj->m_pObj;
if ( pObj==NULL )
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::BuildTransmitBuffer: Queue contains NULL object!"), WBEM_E_INVALID_OPERATION);
ULONG ulLen = pFinObj->m_uSize;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check to see if we have reached the max batch size yet.
// If so, we should break otherwise, update totals and continue
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// paulall - added check in case there is no object in queue and the current object
// is greater than the max size...
if ((nBatchBytes != 0) && ((nBatchBytes+ulLen) > g_ulMaxBatchSize ))
{
m_enumBatchStatus = FinalizerBatch_BufferOverFlow;
bBuildingBuffer = false;
break;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// No overflow, update the object count
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nBatchSize++;
nBatchBytes+=ulLen;
nTempAdd++;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// PHASE 2
// -------
// Build the actual transmit buffer
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ULONG OldSize = m_ulAsyncDeliverySize;
ULONG OldCount = m_ulAsyncDeliveryCount;
m_ulQueueSize -= nBatchBytes;
m_ulAsyncDeliverySize = nBatchBytes;
m_ulAsyncDeliveryCount = nBatchSize;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we have a batch to build, lets do it
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_ulAsyncDeliveryCount > 0 )
{
m_apAsyncDeliveryBuffer = new IWbemClassObject* [ m_ulAsyncDeliveryCount ];
if ( m_apAsyncDeliveryBuffer )
{
memset(m_apAsyncDeliveryBuffer,0,sizeof(IWbemClassObject*)*m_ulAsyncDeliveryCount);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now, loop through the object queue and store the IWbemClassObject ptr
// in the batch
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for ( ULONG x = 0; x < m_ulAsyncDeliveryCount; x++ )
{
CWmiFinalizerObj *pObjTmp = 0;
hRes = DequeueObject(&pObjTmp, NULL);
if (FAILED(hRes) )
{
RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::BuildTransmitBuffer, failed to dequeue object [heap corruption]!"), WBEM_E_FAILED);
}
m_apAsyncDeliveryBuffer [ x ] = pObjTmp->m_pObj;
m_apAsyncDeliveryBuffer [ x ] -> AddRef();
delete pObjTmp;
}
}
else
{
m_ulQueueSize += nBatchBytes;
m_ulAsyncDeliverySize = OldSize;
m_ulAsyncDeliveryCount = OldCount;
hRes = WBEM_E_OUT_OF_MEMORY;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Otherwise, we only got a status message.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else
hRes = WBEM_E_FAILED;
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::DeliverSingleObjFromQueue ( )
{
HRESULT hRes = WBEM_S_NO_ERROR;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Ensure destination sink is protected [stress bug]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IWbemObjectSink* pTmp = ReturnProtectedDestinationSink();
if ( !pTmp )
{
CancelCall (__LINE__);
return WBEM_E_CALL_CANCELLED;
}
CReleaseMe myReleaseMe(pTmp);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Retrieve the object from the object queue
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CWmiFinalizerObj* pObj = NULL;
hRes = DequeueObject ( &pObj, NULL );
if ( FAILED(hRes) || !pObj )
hRes = WBEM_E_FAILED;
else
{
if (pObj->m_objectType == CWmiFinalizerObj::object)
{
HANDLE hTimer;
BOOL bStatus = CreateTimerQueueTimer ( &hTimer, NULL, ProxyThreshold, (PVOID) this, g_ulClientCallbackTimeout, 0, WT_EXECUTEONLYONCE|WT_EXECUTEINTIMERTHREAD );
if ( !bStatus )
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 );
delete pObj;
return CancelCall(__LINE__);
}
if ( HasWriteOnlyProps (pObj->m_pObj) )
ZapWriteOnlyProps (pObj->m_pObj);
CWbemObject* pWbemObj = (CWbemObject*) pObj->m_pObj;
m_ulQueueSize-=pWbemObj->GetBlockLength();
IWbemClassObject * pObj_ = pObj->m_pObj;
hRes = DoIndicate(pTmp, 1, &pObj_);
// Client can also tell us to cancel a call by returning WBEM_E_CALL_CANCELLED from Indicate
// We also want to cancel the call if the client is taking way too long to return
if ( FAILED (hRes) || m_bCancelledCall == TRUE )
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, 0 );
DeleteTimerQueueTimer (NULL, hTimer, INVALID_HANDLE_VALUE );
delete pObj;
return CancelCall(__LINE__);
}
else
DeleteTimerQueueTimer (NULL, hTimer, INVALID_HANDLE_VALUE );
}
else if (pObj->m_objectType == CWmiFinalizerObj::status)
{
// ATTGORA: What about the handle? When do we close it?
HANDLE hTimer;
BOOL bStatus = CreateTimerQueueTimer ( &hTimer, NULL, ProxyThreshold, (PVOID) this, g_ulClientCallbackTimeout, 0, WT_EXECUTEONLYONCE|WT_EXECUTEINTIMERTHREAD );
if ( !bStatus )
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 );
delete pObj;
return CancelCall(__LINE__);
}
hRes = DoSetStatus(pTmp, pObj->m_lFlags, pObj->m_hRes, pObj->m_bStr, pObj->m_pObj);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Client can also tell us to cancel a call by returning WBEM_E_CALL_CANCELLED
// from Indicate We also want to cancel the call if the client is taking way
// too long to return
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( FAILED (hRes) || m_bCancelledCall == TRUE )
{
hRes = CancelCall(__LINE__);
}
DeleteTimerQueueTimer (NULL, hTimer, INVALID_HANDLE_VALUE );
if (pObj->m_lFlags == WBEM_STATUS_COMPLETE)
{
{
CInCritSec lock(&m_destCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if (m_pDestSink)
{
ReleaseDestinationSink ( ) ;
m_bSetStatusConsumed = true;
UpdateStatus ( WMI_FNLZR_STATE_CLIENT_COMPLETE );
}
}
CancelTaskInternal();
}
}
delete pObj;
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::DeliverBatch ( )
{
HRESULT hRes = WBEM_NO_ERROR;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Ensure destination sink is protected [stress bug]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IWbemObjectSink* pTmp = ReturnProtectedDestinationSink ( );
if ( !pTmp )
{
ZeroAsyncDeliveryBuffer ( );
CancelCall(__LINE__);
return WBEM_E_CALL_CANCELLED;
}
CReleaseMe myReleaseMe(pTmp);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a timer queue in case we need to time out the call to the client
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HANDLE hTimer;
BOOL bStatus = CreateTimerQueueTimer ( &hTimer, NULL, ProxyThreshold, (PVOID) this, g_ulClientCallbackTimeout, 0, WT_EXECUTEONLYONCE|WT_EXECUTEINTIMERTHREAD );
if ( !bStatus )
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 );
ZeroAsyncDeliveryBuffer ( );
return CancelCall(__LINE__);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we have sensitive data, zap it.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (int i = 0; i < m_ulAsyncDeliveryCount; i++)
{
if ( HasWriteOnlyProps (m_apAsyncDeliveryBuffer[i]) )
ZapWriteOnlyProps (m_apAsyncDeliveryBuffer[i]);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DoIndicate to the client
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hRes = DoIndicate ( pTmp, m_ulAsyncDeliveryCount, m_apAsyncDeliveryBuffer );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Client can also tell us to cancel a call by returning WBEM_E_CALL_CANCELLED
// from Indicate We also want to cancel the call if the client is taking way
// too long to return
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( FAILED (hRes) || m_bCancelledCall == TRUE )
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, 0 );
hRes = CancelCall(__LINE__);
InterlockedCompareExchange ( &m_lCurrentlyCancelling, TRUE, m_lCurrentlyCancelling);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure timer queue is deleted
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DeleteTimerQueueTimer (NULL, hTimer, INVALID_HANDLE_VALUE );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Clean up the async delivery buffer
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ZeroAsyncDeliveryBuffer ( );
return hRes;
}
/*
* =====================================================================================================
|
| BOOL CWmiFinalizer::IsValidDestinationSink ( )
| -----------------------------------------------
|
| Returns TRUE if we have a valid destination sink, FALSE otherwise.
|
|
* =====================================================================================================
*/
BOOL CWmiFinalizer::IsValidDestinationSink ( )
{
BOOL bIsValidDestinationSink = FALSE ;
CInCritSec lock(&m_destCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_pDestSink != NULL )
{
bIsValidDestinationSink = TRUE ;
}
return bIsValidDestinationSink ;
}
/*
* =====================================================================================================
|
| HRESULT CWmiFinalizer::NotifyClientOfCancelledCall ( )
| ------------------------------------------------------
|
| If Client issued a CancelAsync call he/she is potentially waiting to be woken up once the delivery
| of WBEM_E_CALL_CANCELLED is completed.
|
|
* =====================================================================================================
*/
HRESULT CWmiFinalizer::NotifyClientOfCancelledCall ( )
{
HRESULT hRes = WBEM_S_NO_ERROR ;
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_hWaitForSetStatus )
{
SetEvent ( m_hWaitForSetStatus ) ;
m_hWaitForSetStatus = NULL ;
}
return hRes ;
}
/*
* =====================================================================================================
|
| HRESULT CWmiFinalizer::CancelWaitHandle ( )
| -------------------------------------------
|
| Cancels the handle the client may be waiting for in a CancelAsynCall. Clients _will_ wait for a final
| SetStatus to be called before waking up.
|
|
* =====================================================================================================
*/
HRESULT CWmiFinalizer::CancelWaitHandle ( )
{
HRESULT hRes = WBEM_S_NO_ERROR ;
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_hWaitForSetStatus )
{
m_hWaitForSetStatus = NULL ;
}
return hRes ;
}
/*
* =====================================================================================================
|
| HRESULT CWmiFinalizer::SetClientCancellationHandle ( HANDLE hCancelEvent )
| --------------------------------------------------------------------------
|
| Sets the handle that the client is waiting for in case of a CancelAsyncCall.
|
* =====================================================================================================
*/
HRESULT CWmiFinalizer::SetClientCancellationHandle ( HANDLE hCancelEvent )
{
HRESULT hRes = WBEM_S_NO_ERROR ;
CInCritSec lock(&m_arbitratorCS); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_hWaitForSetStatus == NULL )
{
m_hWaitForSetStatus = hCancelEvent ;
}
return hRes ;
}
//***************************************************************************
// ATTGORA: Do we really need to tell a client that 'setstatus' or 'indicates'
// us for cancellation that we are cancelling?
//***************************************************************************
HRESULT CWmiFinalizer::CancelCall()
{
CAutoSignal CancelCallSignal (m_hCancelEvent);
HRESULT hRes;
if ( InterlockedCompareExchange ( &m_bCancelledCall, 1, 0 ) == 0 )
{
hRes = WBEM_NO_ERROR;
m_bCancelledCall = TRUE;
//
// Indicate the cancellation to the client, iff we are not cancelling
// due to a naughty client (i.e a client that didnt return from
// the indicate or setstatus call in a reasonable amount of time
//
if ( !m_bNaughtyClient )
{
//
// Ensure destination sink is protected [stress bug]
//
IWbemObjectSink* pTmp = ReturnProtectedDestinationSink ( );
if ( !pTmp )
{
m_hStatus = CallCancelled;
NotifyAllEnumeratorsOfCompletion ( ) ;
CancelTaskInternal ( ) ;
return WBEM_NO_ERROR;
}
CReleaseMe myReleaseMe(pTmp);
//
// This is an async operation. Need to call setstatus on delivery thread
// Hack: What we do is forcfully insert the setstatus message at the beginning
// of the object queue. Two scenarios:
// 1. If the async delivery thread is waiting, it will be woken up
// 2. If the async delivery thread is delivering, the next object delivered
// will be the status msg.
//
CWmiFinalizerObj *pObj = new CWmiFinalizerObj(0, WBEM_E_CALL_CANCELLED, NULL, NULL); // SEC:REVIEWED 2002-03-22 : Needs EH
if (pObj == NULL)
{
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY,0,0);
SetOperationResult(0,WBEM_E_OUT_OF_MEMORY);
m_hStatus = QueueFailure;
NotifyAllEnumeratorsOfCompletion();
return WBEM_E_OUT_OF_MEMORY;
}
QueueOperation ( pObj );
m_bSetStatusCalled = true;
}
else
{
//
// We have a client that is not being cooperative (not returning within 60s). BAD
// BAD CLIENT!
//
// Try to push a SetStatus (WBEM_E_CALL_CANCELLED) through. Maybe they're not intentially
// trying to be bad, perhaps they're just incompentent and not reading the docs !
//
IWbemObjectSink* pTmp = ReturnProtectedDestinationSink ( );
if ( !pTmp )
{
m_hStatus = CallCancelled;
NotifyAllEnumeratorsOfCompletion ( ) ;
return WBEM_NO_ERROR;
}
CReleaseMe myReleaseMe(pTmp);
//
// This is the absolutely last attempt to notify the client that something
// is going wrong. We dont care about the result of this operation since
// we cant do anything about a failure anyway! More than likey, if this call
// doesnt return the client has messed up again and we're done.
//
DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, 0 ) ;
}
//
// If we dont have a destination sink, who cares? Do some cleanup.
// Tell the arbitrator to do some system wide clean up. This HAS TO
// finish before we continue cleaning up, otherwise we could be destroying
// sinks that are still considered active
//
hRes = CancelTaskInternal();
}
else
hRes = WBEM_E_CALL_CANCELLED;
m_hStatus = CallCancelled;
NotifyAllEnumeratorsOfCompletion ( ) ;
return hRes;
}
//***************************************************************************
//
//***************************************************************************
VOID WINAPI CWmiFinalizer::ProxyThreshold ( PVOID pvContext, BOOLEAN bTimerOrWait )
{
((CWmiFinalizer*)pvContext)->ProxyThresholdImp();
}
//***************************************************************************
//
//***************************************************************************
VOID CWmiFinalizer::ProxyThresholdImp ( )
{
RevertToSelf ( ) ; // SEC:REVIEWED 2002-03-22 : Needs check
UpdateStatus ( WMI_FNLZR_STATE_CLIENT_DEAD );
ERRORTRACE((LOG_WBEMCORE, "Client did not return from a SetStatus or Indicate call within %d ms\n",g_ulClientCallbackTimeout));
m_bNaughtyClient = TRUE;
CancelCall(__LINE__);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::PullObjects(
long lTimeout,
ULONG uCount,
IWbemClassObject** apObjects,
ULONG* puReturned,
CWmiFinalizerEnumerator* pEnum,
BOOL bAddToObjQueue,
BOOL bSetErrorObj
)
{
HRESULT hr = WBEM_NO_ERROR;
BOOL bTimeOutExpired = FALSE;
if (pEnum == 0)
return WBEM_E_INVALID_PARAMETER;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Has SetStatus already been consumed?
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (pEnum->m_bSetStatusConsumed)
{
try
{
*puReturned = 0;
}
catch (...) // untrusted param
{
ExceptionCounter c;
return WBEM_E_INVALID_PARAMETER;
}
return WBEM_S_FALSE;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now we want to loop until we recieved the number of
// objects requested
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ULONG index = 0;
while (index != uCount)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Dequeue the object
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CWmiFinalizerObj *pObj = NULL;
hr = DequeueObject(&pObj, pEnum);
if (hr == WBEM_S_FALSE )
{
if ( !bTimeOutExpired )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If Dequeue returned FALSE it means
// that there are no objects. We should
// wait for them, unless we have been
// told to cancel or we have been
// released
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_hStatus == CallCancelled )
{
hr = WBEM_E_CALL_CANCELLED;
break ;
}
else if ( m_hStatus == RequestReleased )
{
hr = WBEM_E_FAILED;
break;
}
else if ( m_hStatus == QuotaViolation )
{
hr = WBEM_E_QUOTA_VIOLATION;
break;
}
else if (QueueFailure == m_hStatus)
{
hr = WBEM_E_OUT_OF_MEMORY;
break;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Wait for another object to come in...
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DWORD dwRet = CCoreQueue::QueueWaitForSingleObject(pEnum->m_hWaitOnResultSet, lTimeout);
if (dwRet == WAIT_TIMEOUT)
{
bTimeOutExpired = TRUE;
continue;
}
else if ( m_hStatus == CallCancelled )
{
hr = WBEM_E_CALL_CANCELLED;
break ;
}
else if ( m_hStatus == RequestReleased )
{
hr = WBEM_E_FAILED;
break;
}
else if ( m_hStatus == QuotaViolation )
{
hr = WBEM_E_QUOTA_VIOLATION;
break;
}
else if (QueueFailure == m_hStatus)
{
hr = WBEM_E_OUT_OF_MEMORY;
break;
}
else
continue;
}
else
{
hr = WBEM_S_TIMEDOUT;
break;
}
}
if (FAILED(hr))
break;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we recieved a status complete message, simply break out of
// the loop
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ((pObj->m_objectType == CWmiFinalizerObj::status) && (pObj->m_lFlags == WBEM_STATUS_COMPLETE))
{
// Fix for: 175856, 143550
if ( bSetErrorObj && FAILED (pObj->m_hRes) && pObj->m_pObj )
{
m_pCallResult->SetErrorInfo ( ); // SEC:REVIEWED 2002-03-22 : Needs EH
}
hr = pObj->m_hRes;
if (SUCCEEDED ( hr ) )
hr = WBEM_S_FALSE;
pEnum->m_bSetStatusConsumed = true;
delete pObj;
break;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If its a status message
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if (pObj->m_objectType == CWmiFinalizerObj::status )
{
delete pObj;
continue;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If its an object we enqueue it if requested
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else if (pObj->m_objectType == CWmiFinalizerObj::object)
{
if ( bAddToObjQueue )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure we dont trip on nasty client supplied buffers
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
apObjects[index] = pObj->m_pObj;
if (apObjects[index])
{
pObj->m_pObj->AddRef();
}
}
catch (...) // untrusted args
{
ExceptionCounter c;
hr = WBEM_E_INVALID_PARAMETER;
delete pObj;
break;
}
}
delete pObj;
}
else
{
if ( pObj )
{
delete pObj;
}
}
index ++;
}
if (SUCCEEDED(hr))
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure we dont trip on nasty client supplied buffers
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
*puReturned = index;
}
catch (...) // untrusted args
{
ExceptionCounter c;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// need to release all the objects already in the array otherwise they will be leaked...
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( bAddToObjQueue )
{
for (DWORD i = 0; i != index; i++)
{
if (apObjects[i])
apObjects[i]->Release();
}
}
return WBEM_E_INVALID_PARAMETER;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If we fail, clean up the obj array
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
else
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// need to release all the objects already in the array otherwise they will be leaked...
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( bAddToObjQueue )
{
for (DWORD i = 0; i != index; i++)
{
if (apObjects[i])
apObjects[i]->Release(); // SEC:REVIEWED 2002-03-22 : Needs EH
}
}
}
return hr;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::DequeueObject( CWmiFinalizerObj **ppObj, CWmiFinalizerEnumerator* pEnum )
{
CInCritSec cs(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( pEnum != NULL )
{
if (pEnum->m_uCurObjectPosition >= (ULONG)m_objects.Size())
return WBEM_S_FALSE;
ULONG lIndex = pEnum->m_uCurObjectPosition ;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If this is a semisync call we should decrement the wake up call
// flag
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_ulOperationType == Operation_Type_Semisync && pEnum->m_ulSemisyncWakeupCall != 0 )
{
pEnum->m_ulSemisyncWakeupCall--;
}
if ( m_bSetStatusWithError && m_bRestartable )
{
lIndex = 0 ;
}
CWmiFinalizerObj *pStorageObject = (CWmiFinalizerObj*)m_objects[lIndex];
if (m_bRestartable)
{
//We have to hold on to results, so increment cursor position...
pEnum->m_uCurObjectPosition++;
*ppObj = new CWmiFinalizerObj(*pStorageObject); // SEC:REVIEWED 2002-03-22 : Needs EH
if (*ppObj == NULL) // SEC:REVIEWED 2002-03-22 : Needs EH
return WBEM_E_OUT_OF_MEMORY;
}
else
{
//We are not restartable, therefore we need to release everything...
CWmiFinalizerObj *pStorageObject = (CWmiFinalizerObj*)m_objects[0];
m_objects.RemoveAt(0);
*ppObj = pStorageObject;
}
}
else
{
if ( m_uCurObjectPosition >= (ULONG)m_objects.Size() )
return WBEM_S_FALSE;
CWmiFinalizerObj *pStorageObject = (CWmiFinalizerObj*)m_objects[0];
m_objects.RemoveAt(0);
*ppObj = pStorageObject; // SEC:REVIEWED 2002-03-22 : Needs EH
}
return WBEM_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::Skip(
/*[in]*/ long lTimeout,
/*[in]*/ ULONG nCount,
/*[in]*/ CWmiFinalizerEnumerator* pEnum
)
{
ULONG uReturned = 0;
return PullObjects(lTimeout, nCount, NULL, &uReturned, pEnum, FALSE);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::NextAsync ( CWmiFinalizerEnumerator* pEnum )
{
BOOL bRes;
if (pEnum == 0)
return WBEM_E_FAILED;
wmilib::auto_ptr<InsertableEvent> pInsert( new InsertableEvent);
if (NULL == pInsert.get()) return WBEM_E_OUT_OF_MEMORY;
pInsert->pEnum = pEnum;
pInsert->ThreadId = 0;
pEnum->Add_NextAsync(pInsert.get());
bRes = QueueUserWorkItem ( pEnum->ThreadBootstrapNextAsync, pInsert.get(), WT_EXECUTEDEFAULT );
if ( !bRes )
{
pEnum->Remove_NextAsync(pInsert.release()); // let the Remove function to delete the LIST_ENTRY
pEnum->SetCompletionSignalEvent();
return WBEM_E_FAILED;
}
pInsert.release(); // the WorkItem took possession at this point
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::SetSinkToIdentity ( IWbemObjectSink* pSink )
{
HRESULT sc;
// SEC:REVIEWED 2002-03-22 : Assumes valid pSink. Needs EH in case it is garbage.
IClientSecurity * pFromSec = NULL;
sc = pSink->QueryInterface(IID_IClientSecurity, (void **) &pFromSec);
if(sc == S_OK)
{
OLECHAR * pPrincipal = NULL;
DWORD dwAuthnSvc, dwAuthzSvc, dwAuthnLevel, dwImpLevel, dwCapabilities;
sc = pFromSec->QueryBlanket(pSink, &dwAuthnSvc, &dwAuthzSvc,
&pPrincipal,
&dwAuthnLevel, &dwImpLevel,
NULL, &dwCapabilities);
if ( sc==S_OK )
{
sc = pFromSec->SetBlanket(pSink, dwAuthnSvc, dwAuthzSvc,
pPrincipal,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IDENTIFY, // We always call back on System and IDENTITY IMP LEVEL!!!
NULL, dwCapabilities);
if(pPrincipal)
CoTaskMemFree(pPrincipal);
}
pFromSec->Release();
}
return sc;
}
//***************************************************************************
//
// ZapWriteOnlyProps
//
// Removes write-only properties from an object.
// Precondition: Object has been tested for presence of "HasWriteOnlyProps"
// on the object itself.
//
//***************************************************************************
HRESULT CWmiFinalizer::ZapWriteOnlyProps(IWbemClassObject *pObj)
{
if (pObj == 0)
return WBEM_E_INVALID_PARAMETER;
VARIANT v;
VariantInit(&v);
V_VT(&v) = VT_NULL;
SAFEARRAY *pNames = 0;
pObj->GetNames(L"WriteOnly", WBEM_FLAG_ONLY_IF_TRUE, 0, &pNames); // SEC:REVIEWED 2002-03-22 : Assumes success
LONG lUpper;
SafeArrayGetUBound(pNames, 1, &lUpper);
for (long i = 0; i <= lUpper; i++)
{
BSTR strName = 0;
SafeArrayGetElement(pNames, &i, &strName);
pObj->Put(strName, 0, &v, 0);
SysFreeString (strName);
}
SafeArrayDestroy(pNames);
VariantClear (&v);
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// HasWriteOnlyProps
//
// Returns TRUE if object contains any Write only props, otherwise FALSE
//
//***************************************************************************
BOOL CWmiFinalizer::HasWriteOnlyProps ( IWbemClassObject* pObj )
{
BOOL bRes;
if (pObj == 0) return FALSE;
IWbemQualifierSet *pQSet = 0;
HRESULT hRes = pObj->GetQualifierSet(&pQSet);
if (FAILED(hRes))
return FALSE;
hRes = pQSet->Get(L"HasWriteOnlyProps", 0, 0, 0);
if (SUCCEEDED(hRes))
bRes = TRUE;
else
bRes = FALSE;
pQSet->Release();
return bRes;
}
//***************************************************************************
//
// DoSetStatus
//
// Using LowerAuthLevel
//
//***************************************************************************
HRESULT CWmiFinalizer::DoSetStatusCancel(IWbemObjectSink * pSink, HRESULT realError )
{
IWbemClassObject * objParam;
try
{
CErrorObject Error(0);
Error.SetStatusCode(realError);
objParam = Error.GetObject();
}
catch ( CX_Exception & )
{
}
HRESULT hr = DoSetStatus(pSink, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, objParam);
if (objParam) objParam->Release();
return hr;
}
//***************************************************************************
//
// DoSetStatus
//
// Using LowerAuthLevel
//
//***************************************************************************
HRESULT CWmiFinalizer::DoSetStatus(IWbemObjectSink * psink, long lFlags, HRESULT lParam, BSTR strParam,
IWbemClassObject* pObjParam, BOOL bAllowMultipleCalls )
{
HRESULT hres = WBEM_E_FAILED;
//
// In the case of NextAsync we will in fact allow multiple calls to DoSetStatus
//
if ( ( bAllowMultipleCalls == FALSE ) && ( lFlags == WBEM_STATUS_COMPLETE ) )
{
//
// If a setstatus has already been delivered, fail this operation
// This is a must since we support the CancelAsynCall in which case
// there is potential for 2 setstatus msg to be enqueued.
//
{
CCheckedInCritSec cs ( &m_cs ) ; // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_bSetStatusDelivered == TRUE )
{
//
// If a SetStatus has already been delivered (in non-error cases, i.e. not via client cancellation)
// we still may want to try and wake up the client since they may have tried to enter a cancellation
// wait state.
//
cs.Leave ( ) ;
NotifyClientOfCancelledCall ( ) ;
return hres ;
}
else
{
//
// We assume that the delivery will be successfull. If its not, we dont
// want to try again anyway.
//
m_bSetStatusDelivered = TRUE ;
}
}
}
DWORD dwLastAuthnLevel = LOWER_AUTH_LEVEL_NOTSET;
// put this a loop, but use the counter to make sure there is always an exit.
for(int i = 0; i < 10; i ++)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure bad client sink does not trip us
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
hres = psink->SetStatus(lFlags, lParam, strParam, pObjParam);
}
catch (...) // untrusted sink
{
ExceptionCounter c;
hres = WBEM_E_INVALID_PARAMETER;
break;
}
if(!FAILED(hres))
{
break ; // all done, normal exit
}
if ( hres != E_ACCESSDENIED &&
HRESULT_CODE(hres) != RPC_S_SERVER_TOO_BUSY && // When the target is Win9x and
HRESULT_CODE(hres) != RPC_S_UNKNOWN_AUTHN_SERVICE) // the level is above connect
// DFS patch not applied
break;
hres = FinalizerLowerAuthLevel(psink, &dwLastAuthnLevel);
if(FAILED(hres))
break;
}
if ( FAILED (hres) )
{
ERRORTRACE((LOG_WBEMCORE, "Could not SetStatus to remote client, hres =%X\n",hres));
}
if ( lParam == WBEM_E_CALL_CANCELLED )
{
NotifyClientOfCancelledCall ( ) ;
}
if ( lFlags == WBEM_STATUS_COMPLETE && bAllowMultipleCalls == FALSE )
{
NotifyClientOfCancelledCall ( ) ;
CancelTaskInternal ( ) ;
}
return hres;
}
//***************************************************************************
//
// DoSetIndicate
//
// Using LowerAuthLevel
//
//***************************************************************************
HRESULT CWmiFinalizer::DoIndicate(IWbemObjectSink * psink, int nBatchSize, IWbemClassObject **pBatch)
{
HRESULT hres = WBEM_E_FAILED;
DWORD dwLastAuthnLevel = LOWER_AUTH_LEVEL_NOTSET;
// put this a loop, but use the counter to make sure there is always an exit.
for(int i = 0; i < 10; i ++)
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure bad client sink does not trip us
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
hres = psink->Indicate(nBatchSize, pBatch);
}
catch (...) // untrusted sink
{
ExceptionCounter c;
hres = WBEM_E_INVALID_PARAMETER;
break;
}
if(!FAILED(hres))
{
return hres; // all done, normal exit
}
if ( hres != E_ACCESSDENIED &&
HRESULT_CODE(hres) != RPC_S_SERVER_TOO_BUSY && // When the target is Win9x and
HRESULT_CODE(hres) != RPC_S_UNKNOWN_AUTHN_SERVICE) // the level is above connect
break;
hres = FinalizerLowerAuthLevel(psink, &dwLastAuthnLevel);
if(FAILED(hres))
break;
}
ERRORTRACE((LOG_WBEMCORE, "Could not Indicate to remote client, hres %X\n",hres));
return hres;
}
//***************************************************************************
//
// LowerAuth.
//
// Using LowerAuthLevel
//
//***************************************************************************
HRESULT CWmiFinalizer::FinalizerLowerAuthLevel(IWbemObjectSink * psink, DWORD* pdwLastAuthnLevel )
{
IClientSecurity * pFromSec = NULL;
SCODE sc;
try
{
sc = psink->QueryInterface(IID_IClientSecurity, (void **) &pFromSec); // SEC:REVIEWED 2002-03-22 : Assumes entry
}
catch(...)
{
sc = WBEM_E_INVALID_PARAMETER;
}
if(sc == S_OK)
{
OLECHAR * pPrincipal = NULL;
DWORD dwAuthnSvc, dwAuthzSvc, dwAuthnLevel, dwImpLevel, dwCapabilities;
sc = pFromSec->QueryBlanket(psink, &dwAuthnSvc, &dwAuthzSvc,
&pPrincipal,
&dwAuthnLevel, &dwImpLevel,
NULL, &dwCapabilities);
// If we have never retrieved the authentication level before, then we
// should record what it currently is
if ( LOWER_AUTH_LEVEL_NOTSET == *pdwLastAuthnLevel )
{
*pdwLastAuthnLevel = dwAuthnLevel;
}
if (FAILED(sc))
return sc;
if(*pdwLastAuthnLevel == RPC_C_AUTHN_LEVEL_NONE)
return WBEM_E_FAILED;
(*pdwLastAuthnLevel)--; // normal case is to try one lower
sc = pFromSec->SetBlanket(psink, dwAuthnSvc, dwAuthzSvc,
pPrincipal,
*pdwLastAuthnLevel, RPC_C_IMP_LEVEL_IDENTIFY, // We always call back on System and IDENTITY IMP LEVEL!!!
NULL, dwCapabilities);
if(pPrincipal)
CoTaskMemFree(pPrincipal);
pFromSec->Release();
}
return sc;
}
//***************************************************************************
//
// ZeroAsyncDeliveryBuffer
//
// Clears out the async delivery buffer
//
//***************************************************************************
VOID CWmiFinalizer::ZeroAsyncDeliveryBuffer ( )
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Delete the object array
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for ( ULONG i = 0; i < m_ulAsyncDeliveryCount; i++ )
{
m_apAsyncDeliveryBuffer[i]->Release(); // SEC:REVIEWED 2002-03-22 : Needs check for NULLness or EH
}
delete [] m_apAsyncDeliveryBuffer;
m_ulAsyncDeliveryCount = 0;
m_ulAsyncDeliverySize = 0;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::DumpDebugInfo (
/*[in]*/ ULONG uFlags,
/*[in]*/ const BSTR strFile
)
{
HRESULT hRes = WBEM_S_NO_ERROR;
return hRes;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizer::Shutdown(
/*[in]*/ LONG uReason,
/*[in]*/ ULONG uMaxMilliseconds,
/*[in]*/ IWbemContext *pCtx)
{
wmilib::auto_buffer<IUnknown *> ppEnums;
DWORD Len;
{
CInCritSec lock( &m_cs ) ; // SEC:REVIEWED 2002-03-22 : Assumes entry
Len = m_enumerators.Size();
ppEnums.reset(new IUnknown * [Len]);
if (NULL == ppEnums.get()) return WBEM_E_OUT_OF_MEMORY;
for (DWORD i = 0;i<Len;i++)
{
ppEnums[i] = (IUnknown *)m_enumerators[i];
ppEnums[i]->AddRef();
}
}
for (DWORD i = 0;i<Len;i++)
{
IUnknown * p = ppEnums[i];
IWbemWCOSmartEnum * pSmartEnum = NULL;
if (SUCCEEDED(p->QueryInterface(IID_IWbemWCOSmartEnum,(void **)&pSmartEnum)))
{
CoDisconnectObject(pSmartEnum,0);
pSmartEnum->Release();
}
IWbemFetchSmartEnum * pFetch = NULL;
if (SUCCEEDED(p->QueryInterface(IID_IWbemFetchSmartEnum,(void **)&pFetch)))
{
CWmiFinalizerEnumerator * pEnum = (CWmiFinalizerEnumerator *)(void *)p;
if (pEnum->HasSmartEnum() && SUCCEEDED(pFetch->GetSmartEnum(&pSmartEnum)))
{
CoDisconnectObject(pSmartEnum,0);
pSmartEnum->Release();
}
pFetch->Release();
}
CoDisconnectObject(p,0);
p->Release();
}
return S_OK;
}
/*
* ==================================================================================================
|
| HRESULT CWmiFinalizer::NotifyAllEnumeratorsOfCompletion ( )
| -----------------------------------------------------------
|
|
|
* ==================================================================================================
*/
HRESULT CWmiFinalizer::NotifyAllEnumeratorsOfCompletion ( )
{
//
// Cocked, Locked, and ready to Rock
//
CInCritSec _cs ( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
HRESULT hRes = WBEM_S_NO_ERROR ;
for ( int i = 0; i < m_enumerators.Size ( ); i++ )
{
CWmiFinalizerEnumerator* pEnum = (CWmiFinalizerEnumerator*) m_enumerators[i] ;
if ( pEnum )
{
SetEvent ( pEnum->m_hWaitOnResultSet );
}
}
return hRes ;
}
/*
* ==================================================================================================
|
| HRESULT CWmiFinalizer::UnregisterEnumerator ( CWmiFinalizerEnumerator* pEnum )
| ------------------------------------------------------------------------------
|
|
|
* ==================================================================================================
*/
HRESULT CWmiFinalizer::UnregisterEnumerator ( CWmiFinalizerEnumerator* pEnum )
{
//
// Cocked, Locked, and ready to Rock
//
CInCritSec _cs ( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
HRESULT hRes = WBEM_S_NO_ERROR ;
for ( int i = 0; i < m_enumerators.Size ( ); i++ )
{
CWmiFinalizerEnumerator* pEnumerator = (CWmiFinalizerEnumerator*) m_enumerators[i] ;
if ( pEnum == pEnumerator )
{
pEnumerator->InternalRelease ( ) ;
m_enumerators.RemoveAt ( i ) ;
break ;
}
}
return hRes ;
}
//***************************************************************************
//
//***************************************************************************
void CWmiFinalizer::Dump(FILE* f)
{
fprintf(f, "--Finalizer Stats---\n"); // SEC:REVIEWED 2002-03-22 : OK
fprintf(f, " s_Finalizer_ObjectCount = %d\n", s_Finalizer_ObjectCount); // SEC:REVIEWED 2002-03-22 : OK
fprintf(f, " s_FinalizerCallResult_ObjectCount = %d\n", s_FinalizerCallResult_ObjectCount); // SEC:REVIEWED 2002-03-22 : OK
fprintf(f, " s_FinalizerEnum_ObjectCount = %d\n", s_FinalizerEnum_ObjectCount); // SEC:REVIEWED 2002-03-22 : OK
fprintf(f, " s_FinalizerEnumSink_ObjectCount = %d\n", s_FinalizerEnumSink_ObjectCount); // SEC:REVIEWED 2002-03-22 : OK
fprintf(f, " s_FinalizerInBoundSink_ObjectCount = %d\n\n", s_FinalizerInBoundSink_ObjectCount); // SEC:REVIEWED 2002-03-22 : OK
}
// ==========================================================================
// ==========================================================================
// CWmiFinalizerInboundSink
// ==========================================================================
// ==========================================================================
//***************************************************************************
//
//***************************************************************************
CWmiFinalizerInboundSink::CWmiFinalizerInboundSink(CWmiFinalizer *pFinalizer)
: m_lRefCount(0), m_lInternalRefCount (0),m_pFinalizer(pFinalizer), m_bSetStatusCalled(false)
{
InterlockedIncrement ( & s_FinalizerInBoundSink_ObjectCount ) ;
m_pFinalizer->AddRef();
gClientCounter.AddClientPtr(&m_Entry);
}
//***************************************************************************
//
//***************************************************************************
CWmiFinalizerInboundSink::~CWmiFinalizerInboundSink()
{
InterlockedDecrement ( & s_FinalizerInBoundSink_ObjectCount ) ;
gClientCounter.RemoveClientPtr(&m_Entry);
}
//***************************************************************************
//
//***************************************************************************
void CWmiFinalizerInboundSink::CallBackRelease ()
{
if (!m_bSetStatusCalled)
{
//FNLZR_ASSERT(__TEXT("CWmiFinalizerInboundSink::~CWmiFinalizerInboundSink - Released sink without calling SetStatus! Sending WBEM_E_FAILED to client!"), WBEM_E_INVALID_OPERATION);
m_pFinalizer->SetStatus(0, WBEM_E_UNEXPECTED, NULL, NULL);
ERRORTRACE((LOG_WBEMCORE, "Finalizer: Sink released without SetStatus being called\n"));
}
m_pFinalizer->UnregisterInboundSink(this);
m_pFinalizer->Release();
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerInboundSink::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
// SEC:REVIEWED 2002-03-22 : Should we wrap this in EH? <ppvObj> may point to garbage or be NULL
*ppvObj = 0;
if ((IID_IUnknown==riid) || (IID_IWbemObjectSink == riid))
{
*ppvObj = this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerInboundSink::AddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lRefCount);
if ( uNewCount == 1 )
{
InternalAddRef () ;
}
// printf("CWmiFinalizerInboundSink::Release: 0x%p", this);
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerInboundSink::Release()
{
ULONG uNewCount = InterlockedDecrement(&m_lRefCount);
// printf("CWmiFinalizerInboundSink::Release: 0x%p", this);
if (0 == uNewCount)
{
CallBackRelease () ;
InternalRelease () ;
}
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerInboundSink::InternalAddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lInternalRefCount);
// printf("CWmiFinalizerInboundSink::Release: 0x%p", this);
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerInboundSink::InternalRelease()
{
ULONG uNewCount = InterlockedDecrement(&m_lInternalRefCount);
// printf("CWmiFinalizerInboundSink::Release: 0x%p", this);
if (0 == uNewCount)
{
delete this ;
}
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerInboundSink::Indicate(
/*[in]*/ long lObjectCount,
/*[in, size_is(lObjectCount)]*/
IWbemClassObject** apObjArray
)
{
// If someone is trying to indicate NULL objects, reject and return WBEM_E_INVALID_PARAMETER
if ( apObjArray == NULL )
return WBEM_E_INVALID_PARAMETER;
// Update status variable to show that indicate has been called at least once
m_pFinalizer->UpdateStatus ( WMI_FNLZR_STATE_ACTIVE );
// Special case: Call has been cancelled.
if ( m_pFinalizer->IsCallCancelled() )
return WBEM_E_CALL_CANCELLED;
return m_pFinalizer->Indicate(lObjectCount, apObjArray);
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerInboundSink::SetStatus(
/*[in]*/ long lFlags,
/*[in]*/ HRESULT hResult,
/*[in]*/ BSTR strParam,
/*[in]*/ IWbemClassObject* pObjParam
)
{
// Update status variable to show that SetStatus has been called but not yet delivered
// to client
m_pFinalizer->UpdateStatus ( WMI_FNLZR_STATE_CORE_COMPLETE );
// Special case: Call has been cancelled.
if ( m_pFinalizer->IsCallCancelled() )
return WBEM_E_CALL_CANCELLED;
if (lFlags == WBEM_STATUS_COMPLETE)
{
m_bSetStatusCalled = true;
}
return m_pFinalizer->SetStatus(lFlags, hResult, strParam, pObjParam);
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerInboundSink::Set(
/*[in]*/ long lFlags,
/*[in]*/ REFIID riid,
/*[in, iid_is(riid)]*/ void *pComObject
)
{
#ifdef DBG
DebugBreak();
#endif
return WBEM_E_NOT_SUPPORTED;
}
//***************************************************************************
//
//***************************************************************************
CWmiFinalizerEnumerator::CWmiFinalizerEnumerator(CWmiFinalizer *pFinalizer )
:
m_lRefCount(0),
m_lInternalRefCount(0),
m_pFinalizer(pFinalizer),
m_ulCount(0),
m_pDestSink (NULL),
m_hSignalCompletion (NULL),
m_pSec (NULL),
m_XSmartEnum( this ),
m_pEnumMarshal (NULL)
{
//
// Cloning fix. We need to keep the state of the enumerator.
// This means keeping individual wait event as well as object
// position
//
m_hWaitOnResultSet = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == m_hWaitOnResultSet) throw CX_MemoryException();
m_uCurObjectPosition = 0 ;
m_ulSemisyncWakeupCall = 0 ;
m_bSetStatusConsumed = FALSE ;
InterlockedIncrement ( &s_FinalizerEnum_ObjectCount ) ;
m_pFinalizer->AddRef();
InitializeListHead(&m_HeadNextAsync);
gClientCounter.AddClientPtr(&m_Entry);
}
//***************************************************************************
//
//***************************************************************************
CWmiFinalizerEnumerator::~CWmiFinalizerEnumerator()
{
InterlockedDecrement ( & s_FinalizerEnum_ObjectCount ) ;
if ( m_hSignalCompletion )
{
CloseHandle (m_hSignalCompletion);
m_hSignalCompletion = NULL;
}
CloseHandle ( m_hWaitOnResultSet ) ;
m_hWaitOnResultSet = NULL ;
IUnknown * pUnk = (IUnknown *)InterlockedCompareExchangePointer((PVOID *)&m_pEnumMarshal,0,m_pEnumMarshal);
if (pUnk) pUnk->Release();
gClientCounter.RemoveClientPtr(&m_Entry);
}
void CWmiFinalizerEnumerator::CallBackRelease ()
{
m_pFinalizer->SetInternalStatus ( CWmiFinalizer::QueueStatus::RequestReleased );
m_pFinalizer->CancelTaskInternal();
m_pFinalizer->UnregisterEnumerator ( this ) ;
SetEvent ( m_hWaitOnResultSet ); // in case Cancel did not do it
m_clientLock.Enter();
while (!IsListEmpty(&m_HeadNextAsync))
{
m_clientLock.Leave();
Sleep(100);
m_clientLock.Enter();
}
m_clientLock.Leave();
m_pFinalizer->Release();
m_pFinalizer = NULL;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerEnumerator::AddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lRefCount);
if ( uNewCount == 1 )
{
InternalAddRef () ;
}
// printf("CWmiFinalizerCallResult::Release: 0x%p", this);
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerEnumerator::Release()
{
ULONG uNewCount = InterlockedDecrement(&m_lRefCount);
// printf("CWmiFinalizerCallResult::Release: 0x%p", this);
if (0 == uNewCount)
{
_DBG_ASSERT(2 == m_lInternalRefCount);
CallBackRelease () ;
InternalRelease () ;
}
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerEnumerator::InternalAddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lInternalRefCount);
// printf("CWmiFinalizerCallResult::Release: 0x%p", this);
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerEnumerator::InternalRelease()
{
ULONG uNewCount = InterlockedDecrement(&m_lInternalRefCount);
// printf("CWmiFinalizerCallResult::Release: 0x%p", this);
if (0 == uNewCount)
{
delete this ;
}
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
if (NULL == ppvObj) return E_POINTER;
// Added support for IID_IWbemFetchSmartEnum
if ((IID_IUnknown==riid) || (IID_IEnumWbemClassObject==riid) )
{
*ppvObj = this;
AddRef();
return NOERROR;
}
else if ( IID_IWbemFetchSmartEnum == riid )
{
*ppvObj = (IWbemFetchSmartEnum*) this;
AddRef();
return NOERROR;
}
{
*ppvObj = 0;
return E_NOINTERFACE;
}
}
void CWmiFinalizerEnumerator::Add_NextAsync(InsertableEvent * pInsert)
{
CInCritSec ics(&m_clientLock);
InsertTailList(&m_HeadNextAsync,&pInsert->m_Entry);
}
void CWmiFinalizerEnumerator::Remove_NextAsync(InsertableEvent * pInsert)
{
CInCritSec ics(&m_clientLock);
RemoveEntryList(&pInsert->m_Entry);
delete pInsert;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::Reset()
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
BOOL bDidIWait = FALSE;
if (InterlockedCompareExchangePointer(&m_hSignalCompletion,m_hSignalCompletion,0))
{
CCoreQueue::QueueWaitForSingleObject(m_hSignalCompletion, INFINITE);
bDidIWait = TRUE;
}
CInCritSec cs(&m_clientLock); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( m_pFinalizer->IsRestartable ( ) )
{
m_uCurObjectPosition = 0;
m_bSetStatusConsumed = false;
if (bDidIWait) SetCompletionSignalEvent();
return WBEM_NO_ERROR;
}
else
{
if (bDidIWait) SetCompletionSignalEvent();
return WBEM_E_INVALID_OPERATION;
}
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::Next(
/*[in]*/ long lTimeout,
/*[in]*/ ULONG uCount,
/*[out, size_is(uCount), length_is(*puReturned)]*/ IWbemClassObject** apObjects,
/*[out]*/ ULONG* puReturned
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
CInCritSec cs(&m_clientLock); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( ( puReturned == NULL ) || ( apObjects == NULL ) || (lTimeout < 0 && lTimeout != WBEM_INFINITE) )
{
return WBEM_E_INVALID_PARAMETER ;
}
if ( uCount == 0 )
{
return WBEM_S_NO_ERROR;
}
*puReturned = 0 ;
m_ulSemisyncWakeupCall = uCount ;
return m_pFinalizer->PullObjects(lTimeout, uCount, apObjects, puReturned, this );
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::NextAsync(
/*[in]*/ ULONG uCount,
/*[in]*/ IWbemObjectSink* pSink
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
// If delivery sink is NULL
if ( pSink == NULL )
{
return WBEM_E_INVALID_PARAMETER ;
}
// If requested count is 0
if ( uCount == 0 )
{
return WBEM_S_FALSE;
}
HRESULT hRes;
if ( m_hSignalCompletion == NULL )
{
HANDLE hTmpEvent = CreateEvent ( NULL, FALSE, TRUE, NULL );
if (NULL == hTmpEvent) return WBEM_E_FAILED;
if (InterlockedCompareExchangePointer(&m_hSignalCompletion,hTmpEvent,NULL))
{
CloseHandle(hTmpEvent);
}
}
if ( m_pFinalizer->GetInternalStatus() != m_pFinalizer->NoError )
return WBEM_E_FAILED;
CCoreQueue::QueueWaitForSingleObject(m_hSignalCompletion, INFINITE);
if ( m_pFinalizer->GetInternalStatus() != m_pFinalizer->NoError )
{
// Dont forget to wake up any other threads waiting!
SetCompletionSignalEvent();
return WBEM_E_FAILED;
}
if ( m_bSetStatusConsumed )
{
m_pFinalizer->SetSinkToIdentity ( pSink );
m_pFinalizer->DoSetStatus ( pSink, WBEM_STATUS_COMPLETE, m_pFinalizer->GetFinalResult ( ), 0, 0 );
SetCompletionSignalEvent();
return WBEM_S_FALSE ;
}
// If we are already done.
m_pDestSink = pSink;
m_pDestSink->AddRef(); // SEC:REVIEWED 2002-03-22 : Needs EH in case sink is garbage
m_ulCount = uCount;
m_pFinalizer->SetSinkToIdentity ( m_pDestSink );
return m_pFinalizer->NextAsync (this);
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizerEnumerator::_NextAsync ( )
{
HRESULT hRes = WBEM_S_NO_ERROR;
DWORD dwRet;
RevertToSelf ( ); // SEC:REVIEWED 2002-03-22 : Needs check
// Grab the client lock. All remainding ::NextAsync calls will be queued up
CInCritSec cs(&m_clientLock); // SEC:REVIEWED 2002-03-22 : Assumes entry
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Is the operation complete? If so, we should notify the sink
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if ( m_bSetStatusConsumed )
{
HRESULT hFinalRes;
m_pFinalizer->GetOperationResult ( 0, INFINITE, &hFinalRes );
m_pFinalizer->DoSetStatus ( m_pDestSink, WBEM_STATUS_COMPLETE, hFinalRes, 0, 0 );
hRes = WBEM_S_FALSE;
}
else
{
// NOTE [marioh] : This is no longer needed since we've decided to go with the Win2k solution
// for the time being.
// If we fail to impersonate, we dont continue!!!!
//CAutoRevert AutoRevert (m_pFinalizer);
//if ( AutoRevert.IsImpersonated() == FALSE )
// return WBEM_E_CRITICAL_ERROR;
IWbemClassObject **pArray = new IWbemClassObject *[m_ulCount];
if (pArray == NULL)
{
m_pFinalizer->DoSetStatus ( m_pDestSink, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 );
}
else
{
ULONG uReturned = 0;
m_pFinalizer->SetSemisyncWakeupCall (m_ulCount);
HRESULT hr = m_pFinalizer->PullObjects(INFINITE, m_ulCount, pArray, &uReturned, this, TRUE, FALSE );
if ( FAILED (hr) )
{
if ( hr == WBEM_E_CALL_CANCELLED )
{
m_pFinalizer->DoSetStatus (m_pDestSink, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, 0);
}
}
if (SUCCEEDED(hr) && uReturned)
{
for (int i=0; i!=uReturned; i++)
{
if ( m_pFinalizer->HasWriteOnlyProps (pArray[i]) )
m_pFinalizer->ZapWriteOnlyProps (pArray[i]);
}
hr = m_pFinalizer->DoIndicate(m_pDestSink, uReturned, pArray);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Cleanup the array
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (ULONG i = 0; i != uReturned; i++)
{
pArray[i]->Release();
}
}
delete [] pArray;
if ( SUCCEEDED (hr) )
{
// If number of requested objects == number of objects delivered, SetStatus (WBEM_S_NO_ERROR)
if ( uReturned == m_ulCount )
{
m_pFinalizer->DoSetStatus (m_pDestSink, WBEM_STATUS_COMPLETE, WBEM_S_NO_ERROR, 0, 0, TRUE );
}
// If less objects are delivered, SetStatus (WBEM_S_FALSE)
else
{
m_pFinalizer->DoSetStatus (m_pDestSink, WBEM_STATUS_COMPLETE, WBEM_S_FALSE, 0, 0, TRUE );
}
}
else
{
m_pFinalizer->DoSetStatusCancel (m_pDestSink, hr );
}
}
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
DWORD WINAPI CWmiFinalizerEnumerator::ThreadBootstrapNextAsync ( PVOID pParam )
{
HRESULT hRes;
InsertableEvent * pInsert;
CWmiFinalizerEnumerator* pEnum;
pInsert = (InsertableEvent *)pParam;
pInsert->ThreadId = GetCurrentThreadId();
pEnum = pInsert->pEnum;
try
{
hRes = pEnum->_NextAsync();
}
catch (...)
{
ExceptionCounter c;
};
pEnum->GetDestSink()->Release();
pEnum->NULLDestSink();
pEnum->SetCompletionSignalEvent ();
pEnum->Remove_NextAsync(pInsert);
return hRes;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::Clone(
/*[out]*/ IEnumWbemClassObject** ppEnum
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
CInCritSec cs(&m_clientLock); // SEC:REVIEWED 2002-03-22 : Assumes entry
if ( ppEnum == NULL )
{
return WBEM_E_INVALID_PARAMETER ;
}
// If the enumerator is not restartable, it is forward only, and hence cannot
// be cloned.
if ( !m_pFinalizer->IsRestartable() )
{
return WBEM_E_INVALID_OPERATION;
}
HRESULT hRes = S_OK ;
//
// Get the enumerator
//
hRes = m_pFinalizer->GetResultObject ( m_uCurObjectPosition, IID_IEnumWbemClassObject, (void**)ppEnum ) ;
//
// Keep state information
//
if ( SUCCEEDED ( hRes ) )
{
((CWmiFinalizerEnumerator*)(*ppEnum))->m_uCurObjectPosition = m_uCurObjectPosition ;
((CWmiFinalizerEnumerator*)(*ppEnum))->m_bSetStatusConsumed = m_bSetStatusConsumed ;
}
return hRes;
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::Skip(
/*[in]*/ long lTimeout,
/*[in]*/ ULONG nCount
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
if ( (lTimeout < 0 && lTimeout != WBEM_INFINITE) )
{
return WBEM_E_INVALID_PARAMETER;
}
CInCritSec cs(&m_clientLock); // SEC:REVIEWED 2002-03-22 : Assumes entry
m_ulSemisyncWakeupCall = nCount ;
return m_pFinalizer->Skip(lTimeout, nCount, this ) ;
}
//***************************************************************************
// IWbemFetchSmartEnum
// GetSmartEnum
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::GetSmartEnum ( IWbemWCOSmartEnum** ppSmartEnum )
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
HRESULT hRes;
if (NULL == m_pEnumMarshal)
{
_IWbemEnumMarshaling * pEnum = NULL;
if (FAILED(hRes = CoCreateInstance ( CLSID__WbemEnumMarshaling,
NULL, CLSCTX_INPROC_SERVER, IID__IWbemEnumMarshaling,
(void**) &pEnum )))
{
return hRes;
}
if (InterlockedCompareExchangePointer((PVOID *)&m_pEnumMarshal,pEnum,0))
{
pEnum->Release(); // we've been beaten
}
}
return m_XSmartEnum.QueryInterface( IID_IWbemWCOSmartEnum, (void**) ppSmartEnum );
}
//***************************************************************************
// SmartEnum
// QI
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::XSmartEnum::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
*ppvObj = 0;
if ( IID_IUnknown==riid || IID_IWbemWCOSmartEnum == riid)
{
*ppvObj = (IWbemWCOSmartEnum*)this;
AddRef();
return NOERROR;
}
else
{
return m_pOuter->QueryInterface( riid, ppvObj );
}
}
//***************************************************************************
// SmartEnum
// Addref
//***************************************************************************
ULONG CWmiFinalizerEnumerator::XSmartEnum::AddRef( void )
{
return m_pOuter->AddRef();
}
//***************************************************************************
// SmartEnum
// Release
//***************************************************************************
ULONG CWmiFinalizerEnumerator::XSmartEnum::Release( void )
{
return m_pOuter->Release();
}
//***************************************************************************
// SmartEnum
// Release
//***************************************************************************
STDMETHODIMP CWmiFinalizerEnumerator::XSmartEnum:: Next( REFGUID proxyGUID, long lTimeout, ULONG uCount,
ULONG* puReturned, ULONG* pdwBuffSize, BYTE** pBuffer)
{
if(!m_pOuter->m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
HRESULT hRes = WBEM_S_NO_ERROR;
IWbemClassObject** apObj = new IWbemClassObject* [uCount];
if ( !apObj )
hRes = WBEM_E_OUT_OF_MEMORY;
else
{
// Call next on real enumerator
hRes = m_pOuter->Next ( lTimeout, uCount, apObj, puReturned );
if ( SUCCEEDED (hRes) )
{
if ( *puReturned > 0 )
{
HRESULT hResMarshal = m_pOuter->m_pEnumMarshal->GetMarshalPacket ( proxyGUID, *puReturned, apObj, pdwBuffSize, pBuffer );
if ( FAILED (hResMarshal) )
hRes = hResMarshal;
}
else
{
*pdwBuffSize = 0;
*pBuffer = NULL;
}
for ( ULONG ulIn=0; ulIn < *puReturned; ulIn++ )
{
try
{
apObj[ulIn]->Release();
}
catch(...)
{
}
}
}
delete [] apObj;
}
return hRes;
}
// ===================================================================================================================================================
// ===================================================================================================================================================
//***************************************************************************
//
//***************************************************************************
CWmiFinalizerCallResult::CWmiFinalizerCallResult (
CWmiFinalizer *pFinalizer
) : m_lInternalRefCount(0),
m_pFinalizer(pFinalizer),
m_lFlags(-1),
m_hResult(0),
m_strParam(0),
m_pObj(0),
m_pServices(0),
m_bGotObject(false),
m_bGotServices(false),
m_pErrorObj(NULL),
m_lRefCount(0)
{
InterlockedIncrement ( & s_FinalizerCallResult_ObjectCount );
gClientCounter.AddClientPtr(&m_Entry);
}
//***************************************************************************
//
//***************************************************************************
CWmiFinalizerCallResult::~CWmiFinalizerCallResult()
{
InterlockedDecrement ( & s_FinalizerCallResult_ObjectCount ) ;
if (m_pObj)
m_pObj->Release();
SysFreeString(m_strParam);
if (m_pServices)
m_pServices->Release();
if (m_pErrorObj)
m_pErrorObj->Release();
gClientCounter.RemoveClientPtr(&m_Entry);
}
//***************************************************************************
//
//***************************************************************************
STDMETHODIMP CWmiFinalizerCallResult::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
*ppvObj = 0;
if ((IID_IUnknown==riid) || (IID_IWbemCallResult == riid))
{
*ppvObj = this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerCallResult::AddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lRefCount);
if (uNewCount == 1)
m_pFinalizer->AddRef () ;
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerCallResult::Release()
{
ULONG uNewCount = InterlockedDecrement(&m_lRefCount);
if (uNewCount == 0)
{
m_pFinalizer->CancelTaskInternal();
m_pFinalizer->Release () ;
}
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerCallResult::InternalAddRef()
{
ULONG uNewCount = InterlockedIncrement(&m_lInternalRefCount);
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
ULONG CWmiFinalizerCallResult::InternalRelease()
{
ULONG uNewCount = InterlockedDecrement(&m_lInternalRefCount);
if (0 == uNewCount)
{
delete this ;
}
return uNewCount;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizerCallResult::GetResultObject(
/*[in]*/ long lTimeout,
/*[out]*/ IWbemClassObject** ppResultObject
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
if ( ( ppResultObject==NULL ) || (lTimeout < 0 && lTimeout != WBEM_INFINITE) )
{
return WBEM_E_INVALID_PARAMETER ;
}
if (!m_bGotObject)
{
HRESULT hrResult = WBEM_S_NO_ERROR ;
HRESULT hr = m_pFinalizer->GetOperationResult(0, lTimeout, &hrResult);
if (FAILED(hr))
{
return WBEM_E_FAILED ;
}
else if (hr == WBEM_S_TIMEDOUT)
{
return WBEM_S_TIMEDOUT;
}
else if ( FAILED ( hrResult ) )
{
return hrResult ;
}
if (FAILED(hrResult))
SetErrorInfo();
{
CWmiFinalizerObj *pFinalizerObj=NULL;
bool bFinished = false;
HRESULT hRes = WBEM_E_NOT_FOUND;
while (!bFinished)
{
hRes = m_pFinalizer->GetNextObject(&pFinalizerObj);
if (FAILED(hRes))
{
return WBEM_E_FAILED ;
}
else if (hRes == WBEM_S_FALSE)
{
return WBEM_S_TIMEDOUT;
}
if (pFinalizerObj->m_objectType == CWmiFinalizerObj::object)
{
m_bGotObject = true;
m_pObj = pFinalizerObj->m_pObj;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Catch any nasty attempts to crash WinMgmt through bad
// pointers.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
*ppResultObject = pFinalizerObj->m_pObj;
}
catch (...)
{
ExceptionCounter c;
delete pFinalizerObj;
return WBEM_E_INVALID_PARAMETER;
}
if ( pFinalizerObj->m_pObj )
{
//Need 2 add-refs, one because we hold on to it, the other because we pass it back to the user!
pFinalizerObj->m_pObj->AddRef();
pFinalizerObj->m_pObj->AddRef();
}
bFinished = true;
hrResult = WBEM_S_NO_ERROR ;
}
else if ((pFinalizerObj->m_objectType == CWmiFinalizerObj::status) && (pFinalizerObj->m_lFlags == WBEM_STATUS_COMPLETE))
{
hrResult = pFinalizerObj->m_hRes;
bFinished = true;
}
else if (pFinalizerObj->m_objectType == CWmiFinalizerObj::status)
{
//We have a non-completion status object...
}
delete pFinalizerObj;
}
}
return hrResult;
}
else
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Catch any nasty attempts to crash WinMgmt through bad
// pointers.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
try
{
m_pObj->AddRef();
*ppResultObject = m_pObj;
}
catch (...)
{
ExceptionCounter c;
m_pObj->Release ();
return WBEM_E_INVALID_PARAMETER;
}
return WBEM_S_NO_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizerCallResult::GetResultString(
/*[in]*/ long lTimeout,
/*[out]*/ BSTR* pstrResultString
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
if ( ( pstrResultString==NULL ) || (lTimeout < 0 && lTimeout != WBEM_INFINITE) )
{
return WBEM_E_INVALID_PARAMETER ;
}
HRESULT hrResult;
HRESULT hr = m_pFinalizer->GetOperationResult(0, lTimeout, &hrResult);
if (hr != WBEM_S_NO_ERROR)
return hr;
if (FAILED(hrResult))
SetErrorInfo();
//
// BUGBUG duplicated code SysAllocString takes NULL
//
if(m_strParam)
{
try
{
*pstrResultString = SysAllocString(m_strParam);
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_INVALID_PARAMETER;
}
hr = WBEM_S_NO_ERROR;
}
else
{
try
{
*pstrResultString = NULL;
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_INVALID_PARAMETER;
}
if ( SUCCEEDED (hrResult) )
{
hr = WBEM_E_INVALID_OPERATION;
}
else
{
hr = hrResult;
}
}
return hr;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizerCallResult::GetResultServices(
/*[in]*/ long lTimeout,
/*[out]*/ IWbemServices** ppServices
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
if ( ( ppServices==NULL ) || (lTimeout < 0 && lTimeout != WBEM_INFINITE) )
{
return WBEM_E_INVALID_PARAMETER ;
}
if (!m_bGotServices)
{
HRESULT hrResult;
HRESULT hr = m_pFinalizer->GetOperationResult(0, lTimeout, &hrResult);
if (hr != WBEM_S_NO_ERROR)
return hr;
if (FAILED(hrResult))
SetErrorInfo();
if (SUCCEEDED(hrResult))
{
CWmiFinalizerObj *pFinalizerObj=NULL;
HRESULT hRes = m_pFinalizer->GetNextObject(&pFinalizerObj);
if (FAILED(hRes))
return hRes;
if ( hRes==WBEM_S_FALSE )
return WBEM_E_NOT_FOUND;
m_bGotServices = true;
m_pServices = (IWbemServices*)pFinalizerObj->m_pvObj;
if (ppServices)
{
try
{
*ppServices = (IWbemServices*)pFinalizerObj->m_pvObj;
}
catch (...)
{
ExceptionCounter c;
delete pFinalizerObj;
return WBEM_E_INVALID_PARAMETER;
}
if ( pFinalizerObj->m_pvObj )
{
//Need 2 add-refs, one because we hold on to it, the other because we pass it back to the user!
((IWbemServices*)pFinalizerObj->m_pvObj)->AddRef();
((IWbemServices*)pFinalizerObj->m_pvObj)->AddRef();
}
}
delete pFinalizerObj;
}
return hrResult;
}
else
{
try
{
*ppServices = m_pServices;
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_INVALID_PARAMETER;
}
return WBEM_NO_ERROR;
}
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizerCallResult::GetCallStatus(
/*[in]*/ long lTimeout,
/*[out]*/ long* plStatus
)
{
if(!m_Security.AccessCheck())
return WBEM_E_ACCESS_DENIED;
if ( (plStatus == NULL) || (lTimeout < 0 && lTimeout != WBEM_INFINITE) )
return WBEM_E_INVALID_PARAMETER;
HRESULT hrResult;
HRESULT hr = m_pFinalizer->GetOperationResult(0, lTimeout, &hrResult);
if (hr != WBEM_S_NO_ERROR)
{
return hr;
}
try
{
*plStatus = hrResult;
}
catch (...)
{
ExceptionCounter c;
return WBEM_E_INVALID_PARAMETER;
}
if(FAILED(hrResult))
{
SetErrorInfo();
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizerCallResult::GetResult(
/*[in]*/ long lTimeout,
/*[in]*/ long lFlags,
/*[in]*/ REFIID riid,
/*[out, iid_is(riid)]*/ void **ppvResult
)
{
#ifdef DBG
DebugBreak();
#endif
return WBEM_E_NOT_SUPPORTED;
}
//***************************************************************************
//
//***************************************************************************
HRESULT CWmiFinalizerCallResult::SetStatus(
/*[in]*/ long lFlags,
/*[in]*/ HRESULT hResult,
/*[in]*/ BSTR strParam,
/*[in]*/ IWbemClassObject* pObjParam
)
{
if (m_lFlags != -1)
{
SysFreeString(m_strParam);
m_strParam = 0;
}
if (strParam)
{
m_strParam = SysAllocString(strParam);
if (m_strParam == NULL)
return WBEM_E_OUT_OF_MEMORY;
}
m_lFlags = lFlags;
m_hResult = hResult;
if ( m_pErrorObj )
{
m_pErrorObj->Release ( );
}
m_pErrorObj = pObjParam;
if (m_pErrorObj)
{
m_pErrorObj->AddRef();
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//***************************************************************************
void CWmiFinalizerCallResult::SetErrorInfo()
{
if(m_pErrorObj)
{
IErrorInfo* pInfo = NULL;
m_pErrorObj->QueryInterface(IID_IErrorInfo, (void**)&pInfo);
::SetErrorInfo(0, pInfo);
pInfo->Release();
}
}
//***************************************************************************
// CWmiFinalizerObj Methods
//***************************************************************************
/*
* ==================================================================================================
|
| CWmiFinalizerObj::CWmiFinalizerObj(IWbemClassObject *pObj, _IWmiFinalizer* pFin )
| ---------------------------------------------------------------------------------
|
|
|
|
* ==================================================================================================
*/
CWmiFinalizerObj::CWmiFinalizerObj(IWbemClassObject *pObj, _IWmiFinalizer* pFin ) : m_pObj(pObj),
m_objectType(object),
m_lFlags(0),
m_bStr(0),
m_hRes(0) ,
m_pvObj(0),
m_pFin ( pFin ),
m_hArb ( WBEM_S_ARB_NOTHROTTLING )
{
if (m_pObj)
{
m_pObj->AddRef();
CWbemObject* pObjTmp = (CWbemObject*) pObj;
if ( pObjTmp )
{
m_uSize = pObjTmp -> GetBlockLength();
if ( m_pFin )
{
m_hArb = ((CWmiFinalizer*)m_pFin)->ReportMemoryUsage ( 0, m_uSize ) ;
}
}
else
{
m_uSize = 0;
}
}
}
/*
* ==================================================================================================
|
| CWmiFinalizerObj::CWmiFinalizerObj (CWmiFinalizerObj& obj)
| ----------------------------------------------------------
|
| Copyconstructor for CWmiFinalizerObj. This is ONLY used on restartable enumerators.
| Since we keep the objects in the queue when someone grabs an object on a restartable
| enumerator we dont account for this memory to avoid misreporting memory due to
| destruction of finalizer.
|
|
* ==================================================================================================
*/
CWmiFinalizerObj::CWmiFinalizerObj (CWmiFinalizerObj& obj)
{
m_pvObj = obj.m_pvObj;
m_iid = obj.m_iid;
m_uSize = obj.m_uSize;
m_pFin = NULL ;
m_hArb = obj.m_hArb ;
if (m_pvObj)
{
if (m_iid == IID_IUnknown)
{
((IUnknown*)m_pvObj)->AddRef();
}
else if (m_iid == IID_IWbemClassObject)
{
((IWbemClassObject*)m_pvObj)->AddRef();
}
else if (m_iid == IID__IWmiObject)
{
((_IWmiObject*)m_pvObj)->AddRef();
}
else if (m_iid == IID_IWbemServices)
{
((IWbemServices*)m_pvObj)->AddRef();
}
/*
else if (m_iid == IID_IWbemServicesEx)
{
((IWbemServicesEx*)m_pvObj)->AddRef();
}
*/
}
m_pObj = obj.m_pObj;
m_objectType = obj.m_objectType;
m_lFlags = obj.m_lFlags;
if (obj.m_bStr)
m_bStr = SysAllocString(obj.m_bStr);
else
m_bStr = NULL;
m_hRes = obj.m_hRes;
if (m_pObj)
m_pObj->AddRef();
}
/*
* ==================================================================================================
|
| CWmiFinalizerObj(ULONG lFlags, REFIID riid, void *pvObj)
| --------------------------------------------------------
|
|
|
* ==================================================================================================
*/
CWmiFinalizerObj::CWmiFinalizerObj(ULONG lFlags, REFIID riid, void *pvObj) : m_pObj(0),
m_objectType(set),
m_lFlags(lFlags),
m_bStr(0),
m_hRes(0),
m_pvObj(pvObj),
m_iid(riid),
m_pFin ( NULL ),
m_hArb ( WBEM_S_ARB_NOTHROTTLING )
{
m_uSize = 0;
if (m_iid == IID_IUnknown)
{
((IUnknown*)m_pvObj)->AddRef();
}
else if (m_iid == IID_IWbemClassObject)
{
((IWbemClassObject*)m_pvObj)->AddRef();
}
else if (m_iid == IID__IWmiObject)
{
((_IWmiObject*)m_pvObj)->AddRef();
}
else if (m_iid == IID_IWbemServices)
{
((IWbemServices*)m_pvObj)->AddRef();
}
/*
else if (m_iid == IID_IWbemServicesEx)
{
((IWbemServicesEx*)m_pvObj)->AddRef();
}
*/
else
{
memset(&m_iid, 0, sizeof(IID)); // SEC:REVIEWED 2002-03-22 : OK
m_pvObj = 0;
m_objectType = unknown;
}
}
/*
* ==================================================================================================
|
| CWmiFinalizerObj(ULONG lFlags, HRESULT hRes, BSTR bStr, IWbemClassObject *pObj)
| -------------------------------------------------------------------------------
|
|
|
* ==================================================================================================
*/
CWmiFinalizerObj::CWmiFinalizerObj(ULONG lFlags,
HRESULT hRes,
BSTR bStr,
IWbemClassObject *pObj):
m_pObj(pObj),
m_objectType(status),
m_lFlags(lFlags),
m_hRes(hRes),
m_pvObj(0),
m_pFin ( NULL ) ,
m_hArb ( WBEM_S_ARB_NOTHROTTLING )
{
m_uSize = 0;
if (bStr)
m_bStr = SysAllocString(bStr);
else
m_bStr = NULL;
if (m_pObj)
m_pObj->AddRef();
}
/*
* ==================================================================================================
|
| CWmiFinalizerObj::~CWmiFinalizerObj ( )
| ---------------------------------------
|
|
* ==================================================================================================
*/
CWmiFinalizerObj::~CWmiFinalizerObj ( )
{
if (m_bStr)
{
SysFreeString(m_bStr);
}
if (m_pObj)
{
m_pObj->Release();
m_pObj = NULL ;
}
if (m_pvObj)
{
if (m_iid == IID_IUnknown)
{
((IUnknown*)m_pvObj)->Release();
}
else if (m_iid == IID_IWbemClassObject)
{
((IWbemClassObject*)m_pvObj)->Release();
}
else if (m_iid == IID__IWmiObject)
{
((_IWmiObject*)m_pvObj)->Release();
}
else if (m_iid == IID_IWbemServices)
{
((IWbemServices*)m_pvObj)->Release();
}
m_pvObj = NULL ;
}
if ( m_pFin )
{
((CWmiFinalizer*)m_pFin)->ReportMemoryUsage ( 0, -m_uSize ) ;
m_pFin = NULL ;
}
}