/*++ 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 #include "wbemint.h" #include "wbemcli.h" #include "WmiFinalizer.h" #include "coresvc.h" #include "coreq.h" #include #include #include #include #ifndef INITGUID #define INITGUID #endif // // Added ASSERTS // #ifdef DBG //#define __DBG_FINALIZER #endif #ifdef __DBG_FINALIZER CFlexArray g_DbgFinalizers ; LONG g_DbgFinalizerTotalObjCount = 0 ; LONG g_DbgFinalizerTotalObjSize = 0 ; #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 //CThreadPool CWmiFinalizer::m_threadPool; // Shared thread pool amongst all finalizers // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Assertion code // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //!!! Enable verbose assertions if we are a checked build! #ifdef DBG #define FNLZR_ASSERT_ENABLE #endif #if (defined FNLZR_ASSERT_ENABLE) HRESULT _RetFnlzrAssert(TCHAR *msg, HRESULT hres, const char *filename, int line) { TCHAR *buf = new TCHAR[512]; if (buf == NULL) { return hres; } wsprintf(buf, __TEXT("%s\nhres = 0x%X\nFile: %s, Line: %lu\n\nPress Cancel to stop in debugger, OK to continue"), msg, hres, filename, line); int mbRet = MessageBox(0, buf, __TEXT("WMI Assert"), MB_OKCANCEL | MB_ICONSTOP | MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION); delete [] buf; if (mbRet == IDCANCEL) { DebugBreak(); } return hres; } #define RET_FNLZR_ASSERT(msg, hres) return _RetFnlzrAssert(msg, hres, __FILE__, __LINE__) #define FNLZR_ASSERT(msg, hres) _RetFnlzrAssert(msg, hres, __FILE__, __LINE__) #else #define RET_FNLZR_ASSERT(msg, hres) return hres #define FNLZR_ASSERT(msg, hres) #endif // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Autorelease IWbemObjectSink // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CAutoRelease { private: IWbemObjectSink* m_pObj; public: CAutoRelease (IWbemObjectSink* pObj) : m_pObj(pObj) {;} ~CAutoRelease () { if ( m_pObj) m_pObj->Release(); } VOID Release ( ) { if ( m_pObj ) { m_pObj->Release ( ) ; m_pObj = NULL ; } } }; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Autosignal event // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CAutoSignal { private: HANDLE m_hEvent; public: CAutoSignal (HANDLE hEvent) : m_hEvent(hEvent) { ; } ~CAutoSignal() { if ( m_hEvent ) SetEvent(m_hEvent); } }; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CWMIFINALIZER // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CWmiFinalizer::CWmiFinalizer() // // Peforms initialization of the finalizer. // // Exceptions thrown: // // FNLZR_Exception -> Init. failed // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CWmiFinalizer::CWmiFinalizer(CCoreServices *pSrvs) : m_lRefCount(0), m_lInternalRefCount(0), m_phTask(NULL), m_pArbitrator(NULL), m_pDestSink(NULL), m_pDestructSink(NULL), m_uForwardingType(forwarding_type_none), m_hresFinalResult(-1), m_pEnumerator(NULL), 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 ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create m_hResultReceived handle // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ m_hResultReceived = CreateEvent(NULL, TRUE, FALSE, NULL); if ( !m_hResultReceived ) throw FNLZR_Exception(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create m_hCancelEvent handle // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ m_hCancelEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if ( !m_hCancelEvent ) throw FNLZR_Exception(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create new callresult // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ m_pCallResult = new CWmiFinalizerCallResult(this); if (m_pCallResult) m_pCallResult->InternalAddRef(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // validate CoreServices pointer // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (!pSrvs) throw FNLZR_Exception(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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, _T(REGKEY_CIMOM)); if ( batchSize.GetLastError() == ERROR_SUCCESS ) { DWORD dwTmp; batchSize.GetDWORD ( _T(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, _T(REGKEY_CIMOM)); if ( batchSize.GetLastError() == ERROR_SUCCESS ) { DWORD dwTmp; batchSize.GetDWORD ( _T(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, _T(REGKEY_CIMOM)); if ( batchSize.GetLastError() == ERROR_SUCCESS ) { DWORD dwTmp; batchSize.GetDWORD ( _T(REGVALUE_QUEUETHRESHOLD), &dwTmp ); if ( batchSize.GetLastError() == ERROR_SUCCESS ) g_ulFinalizerQueueThreshold = (LONG) dwTmp; } } InterlockedIncrement ( & s_Finalizer_ObjectCount ) ; #ifdef __DBG_FINALIZER CInCritSec lock(&m_arbitratorCS); g_DbgFinalizers.Add ( this ) ; #endif } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CWmiFinalizer::~CWmiFinalizer() // // Destructor. Decrements global finalizer object count // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CWmiFinalizer::~CWmiFinalizer() { // CInCritSec lock(&m_arbitratorCS); #ifdef __DBG_FINALIZER if ( !m_bClonedFinalizer ) { _DBG_ASSERT ( m_lMemoryConsumption == 0 ) ; } #endif 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 ; } #ifdef __DBG_FINALIZER { CInCritSec lock(&m_arbitratorCS); for ( int i = 0 ; i < g_DbgFinalizers.Size ( ); i++ ) { if ( this == g_DbgFinalizers[i] ) { g_DbgFinalizers.RemoveAt ( i ) ; } } } #endif } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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]; if ( pObj ) { if ( !m_bClonedFinalizer ) { //ADDBACK: ReportMemoryUsage ( 0, -(pObj->m_uSize) ); } delete pObj; } } m_objects.Empty ( ) ; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Release the destruct sink // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (m_pDestructSink) { //TODO: Need to call in to say we are dying... //Don't know what we are supposed to do with it though! //m_pDestructSink->SetStatus(m_hresFinalResult, NULL, NULL); m_pDestructSink->Release(); } for (int i = 0; i != m_inboundSinks.Size(); i++) { ((CWmiFinalizerInboundSink*)m_inboundSinks[i])->InternalRelease(); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (m_pCallResult) { m_pCallResult->InternalRelease(); m_pCallResult = NULL ; } // // Release all enumerators associated with this finalizer // { CInCritSec cs ( &m_cs ) ; 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); HRESULT hRes = WBEM_E_FAILED; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Do we have a valid task? // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (m_phTask) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Do we have a valid arbitrator? // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (m_pArbitrator) { hRes = m_pArbitrator->UnregisterTask(m_phTask); } // // Removed this code due to memory reporting. We _used_ to // release the task immediately after completion AND before // the finalizer was destructed. This does not work anymore // since we need the task around due to potential objects still // left in the queue which need to be removed @ the point of // destruction // /* // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Release the task and NULL it // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if ( m_phTask ) { m_phTask->Release(); m_phTask = NULL; } */ } return hRes; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CWmiFinalizer::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) // // Std implementation of QI // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STDMETHODIMP CWmiFinalizer::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) { *ppvObj = 0; if (IID_IUnknown==riid || IID__IWmiFinalizer==riid) { *ppvObj = (_IWmiCache*)this; AddRef(); return NOERROR; } return E_NOINTERFACE; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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); if (m_pDestSink) { m_pDestSink->Release(); 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 ; #ifdef __DBG_FINALIZER _DBG_ASSERT ( m_phTask != NULL ) ; #endif 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); m_phTask = phTask; m_phTask->AddRef(); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Register the finalizer with the arbitrator // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { CInCritSec lock(&m_arbitratorCS); 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 - extra flags - initially has to be 0 // 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 pSink ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Parameter validation // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (m_pDestSink != NULL) RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetDestinationSink - m_pDestSink != NULL"), WBEM_E_INVALID_OPERATION); if ((pSink == 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) && (riid != IID_IWbemObjectSinkEx)) RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetDestinationSink - iid myst be IID_IWbemObjectSink or IID_IWbemObjectSinkEx"), WBEM_E_INVALID_PARAMETER); m_iidDestSink = riid; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Set the destination sink, AddRef it and set the impersonation level // to identity // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { CInCritSec lock(&m_destCS); m_pDestSink = (IWbemObjectSink*)pSink; m_pDestSink->AddRef(); 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]*/ IWbemObjectSinkEx *pSink ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Parameter validation // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (m_pDestructSink != NULL) RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetSelfDestructCallback - m_pDestructSink != NULL"), WBEM_E_INVALID_OPERATION); if ((pSink == NULL) || (uFlags != 0)) RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::SetSelfDestructCallback - ((pSink == NULL) || (uFlags != 0))"), WBEM_E_INVALID_PARAMETER); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Set and AddRef // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ m_pDestructSink = pSink; m_pDestructSink->AddRef(); return WBEM_NO_ERROR; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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]*/ IWbemObjectSinkEx **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 CInCritSec autoLock(&m_cs); int nRet = m_inboundSinks.Add(pNewSink); if (nRet != CFlexArray::no_error) { pNewSink->Release(); if (nRet == CFlexArray::out_of_memory) return WBEM_E_OUT_OF_MEMORY; else RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::NewInboundSink - Failed to add sink to array!"), WBEM_E_FAILED); } else { pNewSink->InternalAddRef(); } *pSink = pNewSink; 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) { //They want us to return them an enumerator object! //We only allow 1 to be returned! //if (m_pEnumerator != NULL) /*if ( m_enumerators.Size ( ) > 1 ) RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::GetResultObject - Asked for more than 1 enumerator!"), WBEM_E_INVALID_OPERATION); if (m_pDestSink != NULL) RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::GetResultObject - Asked for enumerator when there is a destination sink!"), WBEM_E_INVALID_OPERATION);*/ //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; //m_pEnumerator = NULL; } 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 ) ; // // 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) || (riid == IID_IWbemCallResultEx)) { if (m_pCallResult == NULL) { m_pCallResult = new CWmiFinalizerCallResult(this); if (m_pCallResult == NULL) return WBEM_E_OUT_OF_MEMORY; else m_pCallResult->InternalAddRef () ; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Make sure nasty client does not crash us // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ try { m_pCallResult->AddRef(); *ppObj = m_pCallResult; } catch (...) // untrusted param { ExceptionCounter c; m_pCallResult->Release (); m_pCallResult->InternalRelease () ; m_pCallResult = NULL; 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(); } 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; if ( FAILED ( m_hresFinalResult ) ) { m_pCallResult->SetErrorInfo ( ); } 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); if ( m_pDestSink==NULL ) { return NULL; } else { pTmp = m_pDestSink; pTmp->AddRef(); } } 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 ( ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // First we tell the arbitrator about the delivery thread // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { CInCritSec lock(&m_arbitratorCS); 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); { if ( !m_bSetStatusEnqueued ) { bKeepDelivering = FALSE; m_lCurrentlyDelivering = FALSE; } else { bKeepDelivering = TRUE; } } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Tell the arbitrator that the thread is done // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { CInCritSec lock(&m_arbitratorCS); 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); 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); 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; //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); for (int i = 0; i != m_inboundSinks.Size(); i++) { if (m_inboundSinks[i] == pSink) { pSink->InternalRelease () ; 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::SendErrorObject() { if ( m_pErrorObject ) { IWbemObjectSink* pTmp; { CInCritSec lock(&m_destCS); if ( m_pDestSink==NULL ) return WBEM_NO_ERROR; pTmp = m_pDestSink; pTmp->AddRef(); } CAutoRelease myReleaseMe(pTmp); pTmp->SetStatus(0, this->m_hresFinalResult, L"todo!", m_pErrorObject); } return WBEM_NO_ERROR; } */ //*************************************************************************** // //*************************************************************************** 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); 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 ) 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; } CAutoRelease myReleaseMe(pTmp); hRes = DoIndicate ( pTmp, lObjectCount, apObjArray ); // 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 ); } hRes = WBEM_E_CALL_CANCELLED; myReleaseMe.Release ( ) ; ReleaseDestinationSink ( ) ; CancelCall(); } } else { for (long lIndex = 0; lIndex != lObjectCount; lIndex++) { if ( apObjArray[lIndex] ) { // THIS FIX IS TEMP. REMOVED PENDING DCOM TEAM ANSWERS!!! // If we are trying to indicate an object bigger than max size do the following: // 1. SetStatus to client WBEM_E_INVALID_OBJECT // 2. Return invalid object to caller /*if ( pAlias->GetBlockLength() > MAX_SINGLE_OBJECT_SIZE ) { SetStatus ( 0, WBEM_E_INVALID_OBJECT, 0, 0 ); return WBEM_E_INVALID_OBJECT; }*/ CWmiFinalizerObj *pFinalizerObj = new CWmiFinalizerObj(apObjArray[lIndex], this); if (pFinalizerObj == NULL) return WBEM_E_OUT_OF_MEMORY; HRESULT hr = QueueOperation(pFinalizerObj); if (FAILED(hr)) { return hr; } } } } return hRes; } //*************************************************************************** // //*************************************************************************** HRESULT CWmiFinalizer::Set( /*[in]*/ long lFlags, /*[in]*/ REFIID riid, /*[in, iid_is(riid)]*/ void *pComObject ) { CWmiFinalizerObj *pFinalizerObj = new CWmiFinalizerObj(lFlags, riid, pComObject); 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); 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 ) { if (m_pCallResult == NULL) { m_pCallResult = new CWmiFinalizerCallResult(this); if (m_pCallResult == NULL) return WBEM_E_OUT_OF_MEMORY; m_pCallResult->InternalAddRef () ; } m_pCallResult->SetStatus(lFlags, hResult, strParam, pObjParam); //m_pErrorObject = pObjParam; } HRESULT ourhres = WBEM_E_FAILED; // Special case for cancellations if ( hResult == WBEM_E_CALL_CANCELLED ) { ourhres = CancelCall() ; //CancelTaskInternal ( ) ; } else { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Once again, we have to special case ESS! Lack of trust???? // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if ( (m_uForwardingType == forwarding_type_fast) && (m_ulOperationType == Operation_Type_Async)) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Do we have a valid object sink? // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IWbemObjectSink* pTmp = ReturnProtectedDestinationSink ( ); CAutoRelease 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 ( ) ; //SetEvent ( m_hNewThreadRequests ); // Make sure we wake up any potential clients stuck in PullObjects SetOperationResult(0, hResult); { CInCritSec lock(&m_destCS); 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 ; } } } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // No special casing needed. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ else { //Send the request to the user... CWmiFinalizerObj *pObj = new CWmiFinalizerObj(lFlags, hResult, strParam, pObjParam); if (pObj == NULL) { IWbemObjectSink* pTmp = ReturnProtectedDestinationSink ( ); CAutoRelease myReleaseMe(pTmp); if ( pTmp ) { DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 ) ; } return WBEM_E_OUT_OF_MEMORY; } ourhres = QueueOperation(pObj); if (lFlags == WBEM_STATUS_COMPLETE) { SetOperationResult(0, hResult); //SetEvent ( m_hNewThreadRequests ); // Make sure we wake up any potential clients stuck in PullObjects NotifyAllEnumeratorsOfCompletion ( ) ; // // Lock the task // CWmiTask* pTask = NULL ; { CInCritSec lock(&m_arbitratorCS); if ( m_phTask ) { pTask = (CWmiTask*) m_phTask ; pTask->AddRef ( ) ; } } CReleaseMe _r ( pTask ) ; if ( pTask ) { pTask->SetTaskResult ( hResult ) ; } ((CWmiArbitrator*) m_pArbitrator)->UnregisterTaskForEntryThrottling ( (CWmiTask*) m_phTask ) ; //CancelTaskInternal ( ) ; } } } return ourhres; } //*************************************************************************** // //*************************************************************************** HRESULT CWmiFinalizer::QueueOperation(CWmiFinalizerObj *pObj) { LONG lDelta = 0; HRESULT hRes = WBEM_S_NO_ERROR; CCheckedInCritSec cs ( &m_cs ) ; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 ; int nRet = m_objects.InsertAt ( 0, pObj ); if ( nRet != CFlexArray::no_error ) { return WBEM_E_OUT_OF_MEMORY; } } else { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Normal Add object to queue // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int nRet = m_objects.Add(pObj); if (nRet != CFlexArray::no_error) { delete pObj; if (nRet == CFlexArray::out_of_memory) return WBEM_E_OUT_OF_MEMORY; else RET_FNLZR_ASSERT(__TEXT("CWmiFinalizer::QueueOperation - Failed to add object to table!"), WBEM_E_FAILED); } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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; if ( pObj->m_objectType == CWmiFinalizerObj::object ) { //hArb = ReportMemoryUsage ( 0, 0 ) ; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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. MAYDAY! MAYDAY! 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 ( ) ; } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 ) ) ) { if ( pEnum->m_hWaitOnResultSet ) { 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); 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); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 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 (); return WBEM_E_CALL_CANCELLED; } CAutoRelease 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(); } if ( HasWriteOnlyProps (pObj->m_pObj) ) ZapWriteOnlyProps (pObj->m_pObj); CWbemObject* pWbemObj = (CWbemObject*) pObj->m_pObj; m_ulQueueSize-=pWbemObj->GetBlockLength(); IWbemClassObject** apObj = new IWbemClassObject* [1]; if ( !apObj ) { DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 ); DeleteTimerQueueTimer (NULL, hTimer, INVALID_HANDLE_VALUE ); delete pObj; return CancelCall (); } apObj[0] = pObj->m_pObj; hRes = DoIndicate(pTmp, 1, apObj); delete [] apObj; // 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 ) { //if ( hRes == WBEM_E_CALL_CANCELLED || m_bCancelledCall || ( m_bNaughtyClient == TRUE ) ) //{ DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, 0 ); //} DeleteTimerQueueTimer (NULL, hTimer, INVALID_HANDLE_VALUE ); delete pObj; return CancelCall (); } 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(); } 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 (); } DeleteTimerQueueTimer (NULL, hTimer, INVALID_HANDLE_VALUE ); if (pObj->m_lFlags == WBEM_STATUS_COMPLETE) { { CInCritSec lock(&m_destCS); if (m_pDestSink) { ReleaseDestinationSink ( ) ; m_bSetStatusConsumed = true; UpdateStatus ( WMI_FNLZR_STATE_CLIENT_COMPLETE ); } } CancelTaskInternal(); } } else if ((pObj->m_objectType == CWmiFinalizerObj::set) && (m_iidDestSink == IID_IWbemObjectSinkEx)) { hRes = ((IWbemObjectSinkEx*)m_pDestSink)->Set(pObj->m_lFlags, pObj->m_iid, pObj->m_pvObj); } 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 (); return WBEM_E_CALL_CANCELLED; } CAutoRelease 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(); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 ) { //if ( ( hRes == WBEM_E_CALL_CANCELLED ) || ( m_bCancelledCall == TRUE ) || ( m_bNaughtyClient == TRUE ) ) //{ DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_CALL_CANCELLED, 0, 0 ); //} hRes = CancelCall (); 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); 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); 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); 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); 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; //SetEvent (m_hNewThreadRequests); // Wake up potential threads stuck in delivery NotifyAllEnumeratorsOfCompletion ( ) ; CancelTaskInternal ( ) ; return WBEM_NO_ERROR; } CAutoRelease 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); if (pObj == NULL) { DoSetStatus ( pTmp, WBEM_STATUS_COMPLETE, WBEM_E_OUT_OF_MEMORY, 0, 0 ) ; 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; //SetEvent (m_hNewThreadRequests); // Wake up potential threads stuck in delivery NotifyAllEnumeratorsOfCompletion ( ) ; return WBEM_NO_ERROR; } CAutoRelease 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; //SetEvent (m_hNewThreadRequests); // Wake up potential threads stuck in delivery NotifyAllEnumeratorsOfCompletion ( ) ; return hRes; } //*************************************************************************** // //*************************************************************************** VOID WINAPI CWmiFinalizer::ProxyThreshold ( PVOID pvContext, BOOLEAN bTimerOrWait ) { ((CWmiFinalizer*)pvContext)->ProxyThresholdImp(); } //*************************************************************************** // //*************************************************************************** VOID CWmiFinalizer::ProxyThresholdImp ( ) { RevertToSelf ( ) ; 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(); } //*************************************************************************** // //*************************************************************************** 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; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //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 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 ( ); } 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(); } } } return hr; } //*************************************************************************** // //*************************************************************************** HRESULT CWmiFinalizer::DequeueObject( CWmiFinalizerObj **ppObj, CWmiFinalizerEnumerator* pEnum ) { CInCritSec cs(&m_cs); 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); if (*ppObj == NULL) 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; } 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; HRESULT hRes = WBEM_S_NO_ERROR; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Native Win2k thread dispatching // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pEnum->InternalAddRef(); AddRef(); bRes = QueueUserWorkItem ( pEnum->ThreadBootstrapNextAsync, pEnum, WT_EXECUTEDEFAULT ); if ( !bRes ) { pEnum->InternalRelease(); Release(); pEnum->SetCompletionSignalEvent (); return WBEM_E_FAILED; } if ( pEnum->m_bSetStatusConsumed ) hRes = WBEM_S_FALSE; return hRes; } //*************************************************************************** // //*************************************************************************** HRESULT CWmiFinalizer::SetSinkToIdentity ( IWbemObjectSink* pSink ) { HRESULT sc; 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, dwAuthnLevel, 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) { VARIANT v; VariantInit(&v); V_VT(&v) = VT_NULL; SAFEARRAY *pNames = 0; pObj->GetNames(L"WriteOnly", WBEM_FLAG_ONLY_IF_TRUE, 0, &pNames); 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; 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::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 ) ; 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 != ERROR_ACCESS_DENIED ) 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 != ERROR_ACCESS_DENIED ) break; hres = FinalizerLowerAuthLevel(psink, &dwLastAuthnLevel); if(FAILED(hres)) break; } ERRORTRACE((LOG_WBEMCORE, "Could not SetStatus to remote client, hres %X=\n",hres)); return hres; } //*************************************************************************** // // LowerAuth. // // Using LowerAuthLevel // //*************************************************************************** HRESULT CWmiFinalizer::FinalizerLowerAuthLevel(IWbemObjectSink * psink, DWORD* pdwLastAuthnLevel ) { IClientSecurity * pFromSec = NULL; SCODE 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 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; if(*pdwLastAuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT) *pdwLastAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY; else (*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(); } 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::NotifyAllEnumeratorsOfCompletion ( ) | ----------------------------------------------------------- | | | * ================================================================================================== */ HRESULT CWmiFinalizer::NotifyAllEnumeratorsOfCompletion ( ) { // // Cocked, Locked, and ready to Rock // CInCritSec _cs ( &m_cs ); HRESULT hRes = WBEM_S_NO_ERROR ; for ( int i = 0; i < m_enumerators.Size ( ); i++ ) { CWmiFinalizerEnumerator* pEnum = (CWmiFinalizerEnumerator*) m_enumerators[i] ; if ( pEnum ) { if ( pEnum->m_hWaitOnResultSet ) { 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 ); 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 ; } // ========================================================================== // ========================================================================== // CWmiFinalizerInboundSink // ========================================================================== // ========================================================================== //*************************************************************************** // //*************************************************************************** CWmiFinalizerInboundSink::CWmiFinalizerInboundSink(CWmiFinalizer *pFinalizer) : m_lRefCount(0), m_lInternalRefCount (0),m_pFinalizer(pFinalizer), m_bSetStatusCalled(false) { InterlockedIncrement ( & s_FinalizerInBoundSink_ObjectCount ) ; m_pFinalizer->AddRef(); } //*************************************************************************** // //*************************************************************************** CWmiFinalizerInboundSink::~CWmiFinalizerInboundSink() { InterlockedDecrement ( & s_FinalizerInBoundSink_ObjectCount ) ; } //*************************************************************************** // //*************************************************************************** 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) { *ppvObj = 0; if ((IID_IUnknown==riid) || (IID_IWbemObjectSinkEx==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 ) { if (lFlags != 0) RET_FNLZR_ASSERT(__TEXT("CWmiFinalizerInboundSink::Set - lFlags != 0!"), WBEM_E_INVALID_PARAMETER); return m_pFinalizer->Set(lFlags, riid, pComObject); } //*************************************************************************** // //*************************************************************************** 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) { InterlockedIncrement ( & s_FinalizerEnum_ObjectCount ) ; // // 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); m_uCurObjectPosition = 0 ; m_ulSemisyncWakeupCall = 0 ; m_bSetStatusConsumed = FALSE ; m_pFinalizer->AddRef(); } //*************************************************************************** // //*************************************************************************** CWmiFinalizerEnumerator::~CWmiFinalizerEnumerator() { InterlockedDecrement ( & s_FinalizerEnum_ObjectCount ) ; if ( m_hSignalCompletion ) { CloseHandle ( m_hSignalCompletion ); } if ( m_hWaitOnResultSet ) { SetEvent ( m_hWaitOnResultSet ) ; CloseHandle ( m_hWaitOnResultSet ) ; m_hWaitOnResultSet = NULL ; } // Release the Enum Marshaler { CInCritSec _cs( &m_EnumCS ); if ( m_pEnumMarshal ) { m_pEnumMarshal->Release(); } } } void CWmiFinalizerEnumerator::CallBackRelease () { m_pFinalizer->SetInternalStatus ( m_pFinalizer->RequestReleased ); m_pFinalizer->CancelTaskInternal(); m_pFinalizer->UnregisterEnumerator ( this ) ; m_pFinalizer->Release(); } //*************************************************************************** // //*************************************************************************** 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) { 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) { *ppvObj = 0; // 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; } return E_NOINTERFACE; } //*************************************************************************** // //*************************************************************************** STDMETHODIMP CWmiFinalizerEnumerator::Reset() { if(!m_Security.AccessCheck()) return WBEM_E_ACCESS_DENIED; CInCritSec cs(&m_clientLock); if ( m_pFinalizer->IsRestartable ( ) ) { m_uCurObjectPosition = 0; m_bSetStatusConsumed = false; return WBEM_NO_ERROR; } else 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); 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; { CInCritSec cs(&m_EventCreationLock); if ( m_hSignalCompletion == NULL ) { m_hSignalCompletion = CreateEvent ( NULL, FALSE, TRUE, NULL ); if ( !m_hSignalCompletion ) return WBEM_E_FAILED; } } 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 we are already done. m_pDestSink = pSink; m_pDestSink->AddRef(); 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 ( ); // Grab the client lock. All remainding ::NextAsync calls will be queued up CInCritSec cs(&m_clientLock); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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); 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 ); } } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Cleanup the array if we fail to indicate // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ for (ULONG i = 0; i != uReturned; i++) { pArray[i]->Release(); } delete [] pArray; } } return hRes; } //*************************************************************************** // //*************************************************************************** DWORD WINAPI CWmiFinalizerEnumerator::ThreadBootstrapNextAsync ( PVOID pParam ) { HRESULT hRes; CWmiFinalizerEnumerator* pEnum; try { pEnum = (CWmiFinalizerEnumerator*) pParam; hRes = pEnum->_NextAsync(); } catch (...) { ExceptionCounter c; }; pEnum->GetDestSink()->Release(); pEnum->NULLDestSink(); pEnum->SetCompletionSignalEvent (); pEnum->ReleaseFinalizer(); pEnum->InternalRelease(); return hRes; } //*************************************************************************** // //*************************************************************************** STDMETHODIMP CWmiFinalizerEnumerator::Clone( /*[out]*/ IEnumWbemClassObject** ppEnum ) { if(!m_Security.AccessCheck()) return WBEM_E_ACCESS_DENIED; CInCritSec cs(&m_clientLock); 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 ; //Make sure we have all results before we clone... /*m_pFinalizer->WaitForCompletion(INFINITE); CCoreServices * pSrvs = CCoreServices::CreateInstance(); CReleaseMe _rm(pSrvs); CWmiFinalizer *pFinalizer = new CWmiFinalizer(pSrvs); if (pFinalizer == NULL) return WBEM_E_OUT_OF_MEMORY; pFinalizer->AddRef(); HRESULT hr = pFinalizer->ImportFinalizer(m_pFinalizer); if (FAILED(hr)) { pFinalizer->Release(); return hr; } */ // // 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); m_ulSemisyncWakeupCall = nCount ; return m_pFinalizer->Skip(lTimeout, nCount, this ) ; } //*************************************************************************** // IWbemFetchSmartEnum // GetSmartEnum //*************************************************************************** STDMETHODIMP CWmiFinalizerEnumerator::GetSmartEnum ( IWbemWCOSmartEnum** ppSmartEnum ) { HRESULT hRes = WBEM_S_NO_ERROR; { CInCritSec _cs(&m_EnumCS); if ( !m_pEnumMarshal ) hRes = CoCreateInstance ( CLSID__WbemEnumMarshaling, NULL, CLSCTX_INPROC_SERVER, IID__IWbemEnumMarshaling, (void**) &m_pEnumMarshal ); } return FAILED(hRes) ? hRes : 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) { 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++ ) { apObj[ulIn]->Release(); } } 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 ) ; } //*************************************************************************** // //*************************************************************************** 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(); } //*************************************************************************** // //*************************************************************************** STDMETHODIMP CWmiFinalizerCallResult::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) { *ppvObj = 0; if ((IID_IUnknown==riid) || (IID_IWbemCallResultEx==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; } 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 ) { if(!m_Security.AccessCheck()) return WBEM_E_ACCESS_DENIED; if (ppvResult==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(); 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; if (ppvResult) { if (pFinalizerObj->m_iid == riid) { try { *ppvResult = pFinalizerObj->m_pvObj; } catch (...) { ExceptionCounter c; delete pFinalizerObj; return WBEM_E_INVALID_PARAMETER; } } else hrResult = WBEM_E_FAILED; if ( pFinalizerObj->m_pObj ) { pFinalizerObj->m_pObj->AddRef(); } } delete pFinalizerObj; } return hrResult; } //*************************************************************************** // //*************************************************************************** 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 CWmiFinalizer::Dump(FILE* f) { fprintf(f, "--Finalizer Stats---\n"); fprintf(f, " s_Finalizer_ObjectCount = %d\n", s_Finalizer_ObjectCount); fprintf(f, " s_FinalizerCallResult_ObjectCount = %d\n", s_FinalizerCallResult_ObjectCount); fprintf(f, " s_FinalizerEnum_ObjectCount = %d\n", s_FinalizerEnum_ObjectCount); fprintf(f, " s_FinalizerEnumSink_ObjectCount = %d\n", s_FinalizerEnumSink_ObjectCount); fprintf(f, " s_FinalizerInBoundSink_ObjectCount = %d\n\n", s_FinalizerInBoundSink_ObjectCount); } //*************************************************************************** // //*************************************************************************** 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 ) { #ifdef __DBG_FINALIZER InterlockedIncrement ( &g_DbgFinalizerTotalObjCount ) ; #endif if (m_pObj) { m_pObj->AddRef(); CWbemObject* pObjTmp = (CWbemObject*) pObj; if ( pObjTmp ) { #ifdef __DBG_FINALIZER if ( m_objectType == CWmiFinalizerObj::object ) { _DBG_ASSERT ( m_pFin ) ; } #endif m_uSize = pObjTmp -> GetBlockLength(); if ( m_pFin ) { m_hArb = ((CWmiFinalizer*)m_pFin)->ReportMemoryUsage ( 0, m_uSize ) ; #ifdef __DBG_FINALIZER InterlockedExchangeAdd ( &g_DbgFinalizerTotalObjSize, m_uSize ) ; #endif } } 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)); 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(); } else if (m_iid == IID_IWbemServicesEx) { ((IWbemServicesEx*)m_pvObj)->Release(); } m_pvObj = NULL ; } if ( m_pFin ) { #ifdef __DBG_FINALIZER InterlockedDecrement ( &g_DbgFinalizerTotalObjCount ) ; InterlockedExchangeAdd ( &g_DbgFinalizerTotalObjSize, -m_uSize ) ; #endif ((CWmiFinalizer*)m_pFin)->ReportMemoryUsage ( 0, -m_uSize ) ; m_pFin = NULL ; } }