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
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 ;
|
|
}
|
|
}
|