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

1427 lines
39 KiB

  1. //******************************************************************************
  2. //
  3. // POLLER.CPP
  4. //
  5. // Copyright (C) 1996-1999 Microsoft Corporation
  6. //
  7. //******************************************************************************
  8. #include "precomp.h"
  9. #include <stdio.h>
  10. #include "ess.h"
  11. #include <cominit.h>
  12. #include <callsec.h>
  13. #include "Quota.h"
  14. #include <comdef.h>
  15. #include <GroupsForUser.h>
  16. long g_lNumPollingCachedObjects = 0;
  17. long g_lNumPollingInstructions = 0;
  18. // {2ECF39D0-2B26-11d2-AEC8-00C04FB68820}
  19. const GUID IID_IWbemCallSecurity = {
  20. 0x2ecf39d0, 0x2b26, 0x11d2, {0xae, 0xc8, 0x0, 0xc0, 0x4f, 0xb6, 0x88, 0x20}};
  21. void CBasePollingInstruction::AddRef()
  22. {
  23. InterlockedIncrement(&m_lRef);
  24. }
  25. void CBasePollingInstruction::Release()
  26. {
  27. if(InterlockedDecrement(&m_lRef) == 0)
  28. {
  29. if(DeleteTimer())
  30. {
  31. delete this;
  32. }
  33. else
  34. {
  35. //
  36. // Deep trouble --- cannot delete timer, so it will execute again.
  37. // This means I must leak this instruction (to prevent a crash)
  38. //
  39. }
  40. }
  41. }
  42. CBasePollingInstruction::CBasePollingInstruction(CEssNamespace* pNamespace)
  43. : m_pNamespace(pNamespace), m_strLanguage(NULL), m_strQuery(NULL),
  44. m_pSecurity(NULL), m_lRef(0), m_bUsedQuota(false),
  45. m_bCancelled(false), m_hTimer(NULL)
  46. {
  47. pNamespace->AddRef();
  48. }
  49. CBasePollingInstruction::~CBasePollingInstruction()
  50. {
  51. Destroy();
  52. }
  53. void CBasePollingInstruction::Destroy()
  54. {
  55. //
  56. // The timer is guaranteed to have been deleted by the Release
  57. //
  58. _DBG_ASSERT(m_hTimer == NULL);
  59. if(m_pNamespace)
  60. m_pNamespace->Release();
  61. SysFreeString(m_strLanguage);
  62. SysFreeString(m_strQuery);
  63. if (m_bUsedQuota)
  64. {
  65. if (m_pSecurity)
  66. m_pSecurity->ImpersonateClient();
  67. g_quotas.DecrementQuotaIndex(
  68. ESSQ_POLLING_INSTRUCTIONS,
  69. NULL,
  70. 1);
  71. if (m_pSecurity)
  72. m_pSecurity->RevertToSelf();
  73. }
  74. if(m_pSecurity)
  75. m_pSecurity->Release();
  76. }
  77. bool CBasePollingInstruction::DeleteTimer()
  78. {
  79. HANDLE hTimer = NULL;
  80. {
  81. CInCritSec ics(&m_cs);
  82. hTimer = m_hTimer;
  83. m_bCancelled = true;
  84. }
  85. if(hTimer)
  86. {
  87. if(!DeleteTimerQueueTimer(NULL, hTimer, INVALID_HANDLE_VALUE))
  88. {
  89. return false;
  90. }
  91. m_hTimer = NULL; // no need for cs --- it's cancelled!
  92. }
  93. return true;
  94. }
  95. CWbemTime CBasePollingInstruction::GetNextFiringTime(CWbemTime LastFiringTime,
  96. OUT long* plFiringCount) const
  97. {
  98. *plFiringCount = 1;
  99. CWbemTime Next = LastFiringTime + m_Interval;
  100. if(Next < CWbemTime::GetCurrentTime())
  101. {
  102. // We missed a poll. No problem --- reschedule for later
  103. // =====================================================
  104. return CWbemTime::GetCurrentTime() + m_Interval;
  105. }
  106. else
  107. {
  108. return Next;
  109. }
  110. }
  111. CWbemTime CBasePollingInstruction::GetFirstFiringTime() const
  112. {
  113. // The first time is a random function of the interval
  114. // ===================================================
  115. double dblFrac = (double)rand() / RAND_MAX;
  116. return CWbemTime::GetCurrentTime() + m_Interval * dblFrac;
  117. }
  118. HRESULT CBasePollingInstruction::Initialize(LPCWSTR wszLanguage,
  119. LPCWSTR wszQuery, DWORD dwMsInterval,
  120. bool bAffectsQuota)
  121. {
  122. m_strLanguage = SysAllocString(wszLanguage);
  123. m_strQuery = SysAllocString(wszQuery);
  124. if(m_strLanguage == NULL || m_strQuery == NULL)
  125. return WBEM_E_OUT_OF_MEMORY;
  126. m_Interval.SetMilliseconds(dwMsInterval);
  127. //
  128. // Retrieve the current security object. Even though it is ours, we cannot
  129. // keep it, since it is shared by other threads
  130. //
  131. HRESULT hres = WBEM_S_NO_ERROR;
  132. m_pSecurity = CWbemCallSecurity::MakeInternalCopyOfThread();
  133. if (bAffectsQuota)
  134. {
  135. if ( m_pSecurity )
  136. {
  137. hres = m_pSecurity->ImpersonateClient();
  138. if ( FAILED(hres) )
  139. {
  140. ERRORTRACE((LOG_ESS, "Polling instruction for query %S failed "
  141. "to impersonate client during initialization.\n",
  142. wszQuery ));
  143. return hres;
  144. }
  145. }
  146. hres =
  147. g_quotas.IncrementQuotaIndex(
  148. ESSQ_POLLING_INSTRUCTIONS,
  149. NULL,
  150. 1);
  151. if (m_pSecurity)
  152. m_pSecurity->RevertToSelf();
  153. if (SUCCEEDED(hres))
  154. m_bUsedQuota = true;
  155. }
  156. return hres;
  157. }
  158. void CBasePollingInstruction::staticTimerCallback(void* pParam, BOOLEAN)
  159. {
  160. CBasePollingInstruction* pInst = (CBasePollingInstruction*)pParam;
  161. try
  162. {
  163. pInst->ExecQuery();
  164. }
  165. catch( CX_MemoryException )
  166. {
  167. }
  168. //
  169. // Reschedule the timer, if needed
  170. //
  171. {
  172. CInCritSec ics(&pInst->m_cs);
  173. //
  174. // First, check if the instruction has been cancelled
  175. //
  176. if(pInst->m_bCancelled)
  177. return;
  178. //
  179. // Delete ourselves
  180. //
  181. _DBG_ASSERT(pInst->m_hTimer != NULL);
  182. DeleteTimerQueueTimer(NULL, pInst->m_hTimer, NULL);
  183. CreateTimerQueueTimer(&pInst->m_hTimer, NULL,
  184. (WAITORTIMERCALLBACK)&staticTimerCallback,
  185. pParam,
  186. pInst->m_Interval.GetMilliseconds(),
  187. 0,
  188. WT_EXECUTELONGFUNCTION);
  189. }
  190. }
  191. HRESULT CBasePollingInstruction::Fire(long lNumTimes, CWbemTime NextFiringTime)
  192. {
  193. return ExecQuery();
  194. }
  195. void CBasePollingInstruction::Cancel()
  196. {
  197. m_bCancelled = true;
  198. }
  199. HRESULT CBasePollingInstruction::ExecQuery()
  200. {
  201. HRESULT hres;
  202. // Impersonate
  203. // ===========
  204. if(m_pSecurity)
  205. {
  206. hres = m_pSecurity->ImpersonateClient();
  207. if(FAILED(hres) && (hres != E_NOTIMPL))
  208. {
  209. ERRORTRACE((LOG_ESS, "Impersonation failed with error code %X for "
  210. "polling query %S. Will retry at next polling interval\n",
  211. hres, m_strQuery));
  212. return hres;
  213. }
  214. }
  215. // Execute the query synchrnously (TBD: async would be better)
  216. // ==============================
  217. IWbemServices* pServices = NULL;
  218. hres = m_pNamespace->GetNamespacePointer(&pServices);
  219. if(FAILED(hres))
  220. {
  221. if(m_pSecurity) m_pSecurity->RevertToSelf();
  222. return hres;
  223. }
  224. CReleaseMe rm1(pServices);
  225. DEBUGTRACE((LOG_ESS, "Executing polling query '%S' in namespace '%S'\n",
  226. m_strQuery, m_pNamespace->GetName()));
  227. IEnumWbemClassObject* pEnum;
  228. hres = pServices->ExecQuery(m_strLanguage, m_strQuery,
  229. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY |
  230. WBEM_FLAG_KEEP_SHAPE,
  231. GetCurrentEssContext(), &pEnum);
  232. if(m_pSecurity)
  233. m_pSecurity->RevertToSelf();
  234. if(FAILED(hres))
  235. {
  236. ERRORTRACE((LOG_ESS, "Polling query %S failed with error code %X. "
  237. "Will retry at next polling interval\n", m_strQuery, hres));
  238. return hres;
  239. }
  240. CReleaseMe rm2(pEnum);
  241. // Get the results into an array
  242. // =============================
  243. IWbemClassObject* aBuffer[100];
  244. DWORD dwNumRet;
  245. while(1)
  246. {
  247. hres = pEnum->Next(1000, 100, aBuffer, &dwNumRet);
  248. if(FAILED(hres))
  249. break;
  250. bool bDone = false;
  251. if(hres == WBEM_S_FALSE)
  252. bDone = true;
  253. //
  254. // Check if this query has been cancelled
  255. //
  256. if(m_bCancelled)
  257. {
  258. DEBUGTRACE((LOG_ESS, "Aborting polling query '%S' because its "
  259. "subscription is cancelled\n", m_strQuery));
  260. return WBEM_E_CALL_CANCELLED;
  261. }
  262. for(DWORD dw = 0; dw < dwNumRet; dw++)
  263. {
  264. _IWmiObject* pObj = NULL;
  265. aBuffer[dw]->QueryInterface(IID__IWmiObject, (void**)&pObj);
  266. CReleaseMe rm(pObj);
  267. hres = ProcessObject(pObj);
  268. if(FAILED(hres))
  269. break;
  270. }
  271. for( dw=0; dw < dwNumRet; dw++ )
  272. {
  273. aBuffer[dw]->Release();
  274. }
  275. if(dw < dwNumRet || FAILED(hres))
  276. break;
  277. if(bDone)
  278. break;
  279. }
  280. ProcessQueryDone(hres, NULL);
  281. if(FAILED(hres))
  282. {
  283. ERRORTRACE((LOG_ESS, "Polling query '%S' failed with error code 0x%X. "
  284. "Will retry at next polling interval\n", m_strQuery, hres));
  285. return hres;
  286. }
  287. else
  288. {
  289. DEBUGTRACE((LOG_ESS, "Polling query '%S' done\n", m_strQuery));
  290. }
  291. return WBEM_S_NO_ERROR;
  292. }
  293. BOOL CBasePollingInstruction::CompareTo(CBasePollingInstruction* pOther)
  294. {
  295. if(wcscmp(pOther->m_strLanguage, m_strLanguage)) return FALSE;
  296. if(wcscmp(pOther->m_strQuery, m_strQuery)) return FALSE;
  297. if(pOther->m_Interval.GetMilliseconds() != m_Interval.GetMilliseconds())
  298. return FALSE;
  299. return TRUE;
  300. }
  301. //***************************************************************************
  302. //***************************************************************************
  303. //***************************************************************************
  304. CPollingInstruction::CCachedObject::CCachedObject(_IWmiObject* pObject)
  305. : m_pObject(pObject), m_strPath(NULL)
  306. {
  307. g_lNumPollingCachedObjects++;
  308. // Extract the path
  309. // ================
  310. VARIANT v;
  311. VariantInit(&v);
  312. if (SUCCEEDED(pObject->Get(L"__RELPATH", 0, &v, NULL, NULL)) && (V_VT(&v) == VT_BSTR))
  313. m_strPath = V_BSTR(&v);
  314. // Variant intentionally not cleared
  315. pObject->AddRef();
  316. }
  317. CPollingInstruction::CCachedObject::~CCachedObject()
  318. {
  319. g_lNumPollingCachedObjects--;
  320. if(m_pObject)
  321. m_pObject->Release();
  322. if(NULL != m_strPath)
  323. SysFreeString(m_strPath);
  324. }
  325. int __cdecl CPollingInstruction::CCachedObject::compare(const void* pelem1,
  326. const void* pelem2)
  327. {
  328. CCachedObject* p1 = *(CCachedObject**)pelem1;
  329. CCachedObject* p2 = *(CCachedObject**)pelem2;
  330. if((p1->m_strPath != NULL) && (p2->m_strPath != NULL))
  331. return wbem_wcsicmp(p1->m_strPath, p2->m_strPath);
  332. else if(p1->m_strPath == p2->m_strPath)
  333. return 0;
  334. else
  335. return 1;
  336. }
  337. CPollingInstruction::CPollingInstruction(CEssNamespace* pNamespace)
  338. : CBasePollingInstruction(pNamespace), m_papCurrentObjects(NULL),
  339. m_dwEventMask(0), m_pDest(NULL), m_papPrevObjects(NULL), m_pUser(NULL)
  340. {
  341. g_lNumPollingInstructions++;
  342. }
  343. CPollingInstruction::~CPollingInstruction()
  344. {
  345. g_lNumPollingInstructions--;
  346. SubtractMemory(m_papCurrentObjects);
  347. delete m_papCurrentObjects;
  348. ResetPrevious();
  349. if(m_pDest)
  350. m_pDest->Release();
  351. if(m_pUser)
  352. g_quotas.FreeUser(m_pUser);
  353. }
  354. // This class represents a postponed request to execute a query
  355. class CPostponedQuery : public CPostponedRequest
  356. {
  357. protected:
  358. CPollingInstruction* m_pInst;
  359. public:
  360. CPostponedQuery(CPollingInstruction* pInst) : m_pInst(pInst)
  361. {
  362. m_pInst->AddRef();
  363. }
  364. ~CPostponedQuery()
  365. {
  366. m_pInst->Release();
  367. }
  368. HRESULT Execute(CEssNamespace* pNamespace)
  369. {
  370. return m_pInst->FirstExecute();
  371. }
  372. };
  373. HRESULT CPollingInstruction::FirstExecute()
  374. {
  375. //
  376. // Check if our filter has any hope
  377. //
  378. if(FAILED(m_pDest->GetPollingError()))
  379. {
  380. DEBUGTRACE((LOG_ESS, "Polling query '%S' will not be attempted as \n"
  381. "another polling query related to the same subscription has failed "
  382. "to start with error code 0x%X, deactivating subscription\n",
  383. m_strQuery, m_pDest->GetPollingError()));
  384. return m_pDest->GetPollingError();
  385. }
  386. if(m_bCancelled)
  387. {
  388. DEBUGTRACE((LOG_ESS, "Aborting polling query '%S' because its "
  389. "subscription is cancelled\n", m_strQuery));
  390. return WBEM_E_CALL_CANCELLED;
  391. }
  392. // note that if this function fails, then it will be destroyed when
  393. // the postponed query releases it reference. If this function succeedes
  394. // then tss will hold onto a reference and keep it alive.
  395. //
  396. m_papCurrentObjects = _new CCachedArray;
  397. if( m_papCurrentObjects == NULL )
  398. {
  399. return WBEM_E_OUT_OF_MEMORY;
  400. }
  401. HRESULT hres = ExecQuery();
  402. if ( FAILED(hres) )
  403. {
  404. ERRORTRACE((LOG_ESS, "Polling query '%S' failed on the first try with "
  405. "error code 0x%X.\nDeactivating subscription\n", m_strQuery, hres));
  406. m_pDest->SetPollingError(hres);
  407. return hres;
  408. }
  409. //
  410. // add this instruction to the scheduler
  411. //
  412. if(!CreateTimerQueueTimer(&m_hTimer, NULL,
  413. (WAITORTIMERCALLBACK)&staticTimerCallback,
  414. (void*)(CBasePollingInstruction*)this,
  415. m_Interval.GetMilliseconds(),
  416. 0,
  417. WT_EXECUTELONGFUNCTION))
  418. {
  419. long lRes = GetLastError();
  420. ERRORTRACE((LOG_ESS, "ESS is unable to schedule a timer instruction "
  421. "with the system (error code %d). This operation will be "
  422. "aborted.\n", lRes));
  423. return WBEM_E_FAILED;
  424. }
  425. return WBEM_S_NO_ERROR;
  426. }
  427. HRESULT CPollingInstruction::Initialize(LPCWSTR wszLanguage, LPCWSTR wszQuery,
  428. DWORD dwMsInterval, DWORD dwEventMask,
  429. CEventFilter* pDest)
  430. {
  431. HRESULT hres;
  432. hres = CBasePollingInstruction::Initialize(wszLanguage, wszQuery,
  433. dwMsInterval);
  434. if(FAILED(hres))
  435. return hres;
  436. m_dwEventMask = dwEventMask;
  437. m_pDest = pDest;
  438. pDest->AddRef();
  439. hres = g_quotas.FindUser(pDest, &m_pUser);
  440. if(FAILED(hres))
  441. return hres;
  442. return WBEM_S_NO_ERROR;
  443. }
  444. HRESULT CPollingInstruction::ProcessObject(_IWmiObject* pObj)
  445. {
  446. HRESULT hres;
  447. //
  448. // Make sure that the current object list exists
  449. //
  450. if(m_papCurrentObjects == NULL)
  451. {
  452. m_papCurrentObjects = new CCachedArray;
  453. if(m_papCurrentObjects == NULL)
  454. return WBEM_E_OUT_OF_MEMORY;
  455. }
  456. //
  457. // Check if this query has been cancelled
  458. //
  459. if(m_bCancelled)
  460. {
  461. DEBUGTRACE((LOG_ESS, "Aborting polling query '%S' because its "
  462. "subscription is cancelled\n", m_strQuery));
  463. return WBEM_E_CALL_CANCELLED;
  464. }
  465. //
  466. // Check quotas
  467. //
  468. DWORD dwSize = ComputeObjectMemory(pObj);
  469. hres = g_quotas.IncrementQuotaIndexByUser(ESSQ_POLLING_MEMORY,
  470. m_pUser, dwSize);
  471. if(FAILED(hres))
  472. {
  473. ERRORTRACE((LOG_ESS, "Aborting polling query '%S' because the quota "
  474. "for memory used by polling is exceeded\n", m_strQuery));
  475. return hres;
  476. }
  477. //
  478. // Add the object to the current list
  479. //
  480. CCachedObject* pRecord = _new CCachedObject(pObj);
  481. if(pRecord == NULL || !pRecord->IsValid())
  482. {
  483. delete pRecord;
  484. return WBEM_E_OUT_OF_MEMORY;
  485. }
  486. if(m_papCurrentObjects->Add(pRecord) < 0)
  487. {
  488. delete pRecord;
  489. return WBEM_E_OUT_OF_MEMORY;
  490. }
  491. return WBEM_S_NO_ERROR;
  492. }
  493. DWORD CPollingInstruction::ComputeObjectMemory(_IWmiObject* pObj)
  494. {
  495. DWORD dwSize = 0;
  496. HRESULT hres = pObj->GetObjectMemory( NULL, 0, &dwSize );
  497. if (FAILED(hres) && hres != WBEM_E_BUFFER_TOO_SMALL )
  498. {
  499. return hres;
  500. }
  501. return dwSize;
  502. }
  503. HRESULT CPollingInstruction::ProcessQueryDone( HRESULT hresQuery,
  504. IWbemClassObject* pErrorObj)
  505. {
  506. HRESULT hres;
  507. if(FAILED(hresQuery))
  508. {
  509. //
  510. // If the query failed, retain the previous poll
  511. // result --- that's the best we can do
  512. //
  513. SubtractMemory(m_papCurrentObjects);
  514. delete m_papCurrentObjects;
  515. m_papCurrentObjects = NULL;
  516. //
  517. // Report subscription error
  518. //
  519. return WBEM_S_FALSE;
  520. }
  521. else if ( m_papCurrentObjects == NULL )
  522. {
  523. //
  524. // Query came back empty --- emulate by creating an empty
  525. // m_papCurrentObjects
  526. //
  527. m_papCurrentObjects = new CCachedArray;
  528. if(m_papCurrentObjects == NULL)
  529. return WBEM_E_OUT_OF_MEMORY;
  530. }
  531. //
  532. // Sort the objects by path
  533. //
  534. qsort((void*)m_papCurrentObjects->GetArrayPtr(),
  535. m_papCurrentObjects->GetSize(),
  536. sizeof(CCachedObject*), CCachedObject::compare);
  537. //
  538. // At this point, m_papCurrentObjects contains the sorted results of the
  539. // current query. If this is not the first time, m_papPrevObjects
  540. // contains the previous result. If first time, then all done for now.
  541. //
  542. if( m_papPrevObjects == NULL )
  543. {
  544. m_papPrevObjects = m_papCurrentObjects;
  545. m_papCurrentObjects = NULL;
  546. return WBEM_S_NO_ERROR;
  547. }
  548. //
  549. // Now is the time to compare
  550. //
  551. long lOldIndex = 0, lNewIndex = 0;
  552. while(lNewIndex < m_papCurrentObjects->GetSize() &&
  553. lOldIndex < m_papPrevObjects->GetSize())
  554. {
  555. int nCompare = 1;
  556. BSTR bstr1 = m_papCurrentObjects->GetAt(lNewIndex)->m_strPath,
  557. bstr2 = m_papPrevObjects->GetAt(lOldIndex)->m_strPath;
  558. if((bstr1 != NULL) && (bstr2 != NULL))
  559. nCompare = wbem_wcsicmp(bstr1, bstr2);
  560. else if (bstr1 == bstr2)
  561. nCompare = 0;
  562. else
  563. nCompare = 1;
  564. if(nCompare < 0)
  565. {
  566. // The _new object is not in the old array --- object created
  567. // =========================================================
  568. if(m_dwEventMask & (1 << e_EventTypeInstanceCreation))
  569. {
  570. RaiseCreationEvent(m_papCurrentObjects->GetAt(lNewIndex));
  571. }
  572. lNewIndex++;
  573. }
  574. else if(nCompare > 0)
  575. {
  576. // The old object is not in the _new array --- object deleted
  577. // =========================================================
  578. if(m_dwEventMask & (1 << e_EventTypeInstanceDeletion))
  579. {
  580. RaiseDeletionEvent(m_papPrevObjects->GetAt(lOldIndex));
  581. }
  582. lOldIndex++;
  583. }
  584. else
  585. {
  586. if(m_dwEventMask & (1 << e_EventTypeInstanceModification))
  587. {
  588. // Compare the objects themselves
  589. // ==============================
  590. hres = m_papCurrentObjects->GetAt(lNewIndex)->m_pObject->
  591. CompareTo(
  592. WBEM_FLAG_IGNORE_CLASS | WBEM_FLAG_IGNORE_OBJECT_SOURCE,
  593. m_papPrevObjects->GetAt(lOldIndex)->m_pObject);
  594. if(hres != S_OK)
  595. {
  596. // The objects are not the same --- object changed
  597. // ===============================================
  598. RaiseModificationEvent(
  599. m_papCurrentObjects->GetAt(lNewIndex),
  600. m_papPrevObjects->GetAt(lOldIndex));
  601. }
  602. }
  603. lOldIndex++; lNewIndex++;
  604. }
  605. }
  606. if(m_dwEventMask & (1 << e_EventTypeInstanceDeletion))
  607. {
  608. while(lOldIndex < m_papPrevObjects->GetSize())
  609. {
  610. RaiseDeletionEvent(m_papPrevObjects->GetAt(lOldIndex));
  611. lOldIndex++;
  612. }
  613. }
  614. if(m_dwEventMask & (1 << e_EventTypeInstanceCreation))
  615. {
  616. while(lNewIndex < m_papCurrentObjects->GetSize())
  617. {
  618. RaiseCreationEvent(m_papCurrentObjects->GetAt(lNewIndex));
  619. lNewIndex++;
  620. }
  621. }
  622. // Replace the cached array with the new one
  623. // =========================================
  624. ResetPrevious();
  625. m_papPrevObjects = m_papCurrentObjects;
  626. m_papCurrentObjects = NULL;
  627. return S_OK;
  628. }
  629. HRESULT CPollingInstruction::RaiseCreationEvent(CCachedObject* pNewObj)
  630. {
  631. IWbemClassObject* _pObj = pNewObj->m_pObject;
  632. CEventRepresentation Event;
  633. Event.type = e_EventTypeInstanceCreation;
  634. Event.wsz1 = (LPWSTR)m_pNamespace->GetName();
  635. BSTR strTemp = GetObjectClass(pNewObj);
  636. Event.wsz2 = (LPWSTR)strTemp;
  637. Event.wsz3 = NULL;
  638. Event.nObjects = 1;
  639. Event.apObjects = &_pObj;
  640. CWbemPtr<IWbemEvent> pEventObj;
  641. if(FAILED(Event.MakeWbemObject(m_pNamespace, &pEventObj)))
  642. return WBEM_E_OUT_OF_MEMORY;
  643. // BUGBUG: context
  644. HRESULT hres = m_pDest->Indicate(1, &pEventObj, NULL);
  645. SysFreeString(strTemp);
  646. return hres;
  647. }
  648. HRESULT CPollingInstruction::RaiseDeletionEvent(CCachedObject* pOldObj)
  649. {
  650. IWbemClassObject* _pObj = pOldObj->m_pObject;
  651. CEventRepresentation Event;
  652. Event.type = e_EventTypeInstanceDeletion;
  653. Event.wsz1 = (LPWSTR)m_pNamespace->GetName();
  654. BSTR strTemp = GetObjectClass(pOldObj);
  655. Event.wsz2 = (LPWSTR)strTemp;
  656. Event.wsz3 = NULL;
  657. Event.nObjects = 1;
  658. Event.apObjects = &_pObj;
  659. CWbemPtr<IWbemEvent> pEventObj;
  660. if(FAILED(Event.MakeWbemObject(m_pNamespace, &pEventObj)))
  661. return WBEM_E_OUT_OF_MEMORY;
  662. // BUGBUG: context
  663. HRESULT hres = m_pDest->Indicate(1, &pEventObj, NULL);
  664. SysFreeString(strTemp);
  665. return hres;
  666. }
  667. HRESULT CPollingInstruction::RaiseModificationEvent(CCachedObject* pNewObj,
  668. CCachedObject* pOldObj)
  669. {
  670. IWbemClassObject* apObjects[2];
  671. CEventRepresentation Event;
  672. Event.type = e_EventTypeInstanceModification;
  673. Event.wsz1 = (LPWSTR)m_pNamespace->GetName();
  674. BSTR strTemp = GetObjectClass(pNewObj);
  675. Event.wsz2 = (LPWSTR)strTemp;
  676. Event.wsz3 = NULL;
  677. Event.nObjects = 2;
  678. Event.apObjects = (IWbemClassObject**)apObjects;
  679. Event.apObjects[0] = pNewObj->m_pObject;
  680. Event.apObjects[1] = (pOldObj?pOldObj->m_pObject:NULL);
  681. CWbemPtr<IWbemEvent> pEventObj;
  682. if(FAILED(Event.MakeWbemObject(m_pNamespace, &pEventObj)))
  683. return WBEM_E_OUT_OF_MEMORY;
  684. // BUGBUG: context
  685. HRESULT hres = m_pDest->Indicate(1, &pEventObj, NULL);
  686. SysFreeString(strTemp);
  687. return hres;
  688. }
  689. HRESULT CPollingInstruction::ResetPrevious()
  690. {
  691. HRESULT hres;
  692. SubtractMemory(m_papPrevObjects);
  693. delete m_papPrevObjects;
  694. m_papPrevObjects = NULL;
  695. return S_OK;
  696. }
  697. HRESULT CPollingInstruction::SubtractMemory(CCachedArray* pArray)
  698. {
  699. HRESULT hres;
  700. if(pArray == NULL)
  701. return S_FALSE;
  702. for(int i = 0; i < pArray->GetSize(); i++)
  703. {
  704. _IWmiObject* pObj = pArray->GetAt(i)->m_pObject;
  705. DWORD dwSize = ComputeObjectMemory(pObj);
  706. hres = g_quotas.DecrementQuotaIndexByUser(ESSQ_POLLING_MEMORY,
  707. m_pUser, dwSize);
  708. if(FAILED(hres))
  709. return hres;
  710. }
  711. return S_OK;
  712. }
  713. SYSFREE_ME BSTR CPollingInstruction::GetObjectClass(CCachedObject* pObj)
  714. {
  715. VARIANT v;
  716. VariantInit(&v);
  717. if ( FAILED( pObj->m_pObject->Get(L"__CLASS", 0, &v, NULL, NULL) ) )
  718. {
  719. return NULL;
  720. }
  721. return V_BSTR(&v);
  722. }
  723. //*****************************************************************************
  724. //*****************************************************************************
  725. //
  726. // P o l l e r
  727. //
  728. //*****************************************************************************
  729. //*****************************************************************************
  730. CPoller::CPoller(CEssNamespace* pNamespace)
  731. : m_pNamespace(pNamespace), m_bInResync(FALSE)
  732. {
  733. }
  734. CPoller::~CPoller()
  735. {
  736. }
  737. void CPoller::Clear()
  738. {
  739. CInstructionMap::iterator it = m_mapInstructions.begin();
  740. while(it != m_mapInstructions.end())
  741. {
  742. // Release the refcount this holds on the instructioin
  743. // ===================================================
  744. it->first->Cancel();
  745. it->first->DeleteTimer();
  746. it->first->Release();
  747. it = m_mapInstructions.erase(it);
  748. }
  749. }
  750. HRESULT CPoller::ActivateFilter(CEventFilter* pDest,
  751. LPCWSTR wszQuery, QL_LEVEL_1_RPN_EXPRESSION* pExpr)
  752. {
  753. // Check what kind of events it is looking for
  754. // ===========================================
  755. DWORD dwEventMask = CEventRepresentation::GetTypeMaskFromName(
  756. pExpr->bsClassName);
  757. if((dwEventMask &
  758. ((1 << e_EventTypeInstanceCreation) |
  759. (1 << e_EventTypeInstanceDeletion) |
  760. (1 << e_EventTypeInstanceModification)
  761. )
  762. ) == 0
  763. )
  764. {
  765. // This registration does not involve instance-related events and
  766. // therefore there is no polling involved
  767. // ==============================================================
  768. return WBEM_S_FALSE;
  769. }
  770. // The query is looking for instance-change events. See what classes
  771. // of objects it is interested in.
  772. // =================================================================
  773. CClassInfoArray* paInfos;
  774. HRESULT hres = m_Analyser.GetPossibleInstanceClasses(pExpr, paInfos);
  775. if(FAILED(hres)) return hres;
  776. CDeleteMe<CClassInfoArray> dm2(paInfos);
  777. if(!paInfos->IsLimited())
  778. {
  779. // Analyser could not find any limits on the possible classes.
  780. // Rephrase that as all children of ""
  781. // ===========================================================
  782. CClassInformation* pNewInfo = _new CClassInformation;
  783. if(pNewInfo == NULL)
  784. return WBEM_E_OUT_OF_MEMORY;
  785. pNewInfo->m_wszClassName = NULL;
  786. pNewInfo->m_bIncludeChildren = TRUE;
  787. paInfos->AddClass(pNewInfo);
  788. paInfos->SetLimited(TRUE);
  789. }
  790. // See if it is looking for any dynamic classes.
  791. // =============================================
  792. for(int i = 0; i < paInfos->GetNumClasses(); i++)
  793. {
  794. CClassInfoArray aNonProvided;
  795. hres = ListNonProvidedClasses(
  796. paInfos->GetClass(i), dwEventMask, aNonProvided);
  797. if(FAILED(hres))
  798. {
  799. ERRORTRACE((LOG_ESS,"Failed searching for classes to poll.\n"
  800. "Class name: %S, Error code: %X\n\n",
  801. paInfos->GetClass(i)->m_wszClassName, hres));
  802. return hres;
  803. }
  804. // Increment our quotas if necessary.
  805. DWORD nClasses = aNonProvided.GetNumClasses();
  806. if (nClasses)
  807. {
  808. PSID pSID = pDest->GetOwner( );
  809. if ( pSID && STATUS_SUCCESS != IsUserAdministrator( pSID ) )
  810. {
  811. return WBEM_E_ACCESS_DENIED;
  812. }
  813. if (FAILED(hres = g_quotas.IncrementQuotaIndex(
  814. ESSQ_POLLING_INSTRUCTIONS, pDest, nClasses)))
  815. {
  816. return hres;
  817. }
  818. }
  819. // Institute polling for each class
  820. // ================================
  821. for(int j = 0; j < nClasses; j++)
  822. {
  823. // We have an instance-change event registration where dynamic
  824. // instances are involved. Check if tolerance is specified
  825. // ===========================================================
  826. if(pExpr->Tolerance.m_bExact ||
  827. pExpr->Tolerance.m_fTolerance == 0)
  828. {
  829. return WBEMESS_E_REGISTRATION_TOO_PRECISE;
  830. }
  831. // Tolerance is there. Get the right query for this class
  832. // ======================================================
  833. LPWSTR wszThisQuery = NULL;
  834. hres = m_Analyser.GetLimitingQueryForInstanceClass(
  835. pExpr, *aNonProvided.GetClass(j), wszThisQuery);
  836. CVectorDeleteMe<WCHAR> vdm1(wszThisQuery);
  837. if(FAILED(hres))
  838. {
  839. ERRORTRACE((LOG_ESS,"ERROR: Limiting query extraction failed.\n"
  840. "Original query: %S\nClass: %S\nError code: %X\n",
  841. wszQuery, aNonProvided.GetClass(j)->m_wszClassName, hres));
  842. return hres;
  843. }
  844. DEBUGTRACE((LOG_ESS,"Instituting polling query %S to satisfy event"
  845. " query %S\n", wszThisQuery, wszQuery));
  846. DWORD dwMs = pExpr->Tolerance.m_fTolerance * 1000;
  847. CWbemPtr<CPollingInstruction> pInst;
  848. pInst = _new CPollingInstruction(m_pNamespace);
  849. if(pInst == NULL)
  850. return WBEM_E_OUT_OF_MEMORY;
  851. hres = pInst->Initialize( L"WQL",
  852. wszThisQuery,
  853. dwMs,
  854. aNonProvided.GetClass(j)->m_dwEventMask,
  855. pDest);
  856. if ( SUCCEEDED(hres) )
  857. {
  858. hres = AddInstruction( (DWORD_PTR)pDest, pInst );
  859. }
  860. if ( FAILED(hres) )
  861. {
  862. ERRORTRACE((LOG_ESS,
  863. "ERROR: Polling instruction initialization failed\n"
  864. "Query: %S\nError code: %X\n\n", wszThisQuery, hres));
  865. return hres;
  866. }
  867. }
  868. }
  869. return WBEM_S_NO_ERROR;
  870. }
  871. HRESULT CPoller::AddInstruction( DWORD_PTR dwKey, CPollingInstruction* pInst )
  872. {
  873. HRESULT hr;
  874. CInCritSec ics(&m_cs);
  875. if( m_bInResync )
  876. {
  877. // Search for the instruction in the map
  878. // =====================================
  879. CInstructionMap::iterator it;
  880. for( it=m_mapInstructions.begin(); it != m_mapInstructions.end(); it++)
  881. {
  882. //
  883. // if the filter key is the same and the instructions have the
  884. // same queries, then there is a match. It is not enough to
  885. // do just the filter key, since there can be multiple instructions
  886. // per filter, and it is not enough to do just the instruction
  887. // comparison since multiple filters can have the same polling
  888. // instruction queries. Since there can never be multiple
  889. // instructions with the same query for the same filter,
  890. // comparing both works.
  891. //
  892. if( it->second.m_dwFilterId == dwKey &&
  893. it->first->CompareTo( pInst ) )
  894. {
  895. //
  896. // Found it, set to active but DO NOT add to the generator.
  897. // it is already there
  898. //
  899. it->second.m_bActive = TRUE;
  900. return WBEM_S_FALSE;
  901. }
  902. }
  903. }
  904. //
  905. // add to the instruction to the map.
  906. //
  907. FilterInfo Info;
  908. Info.m_dwFilterId = dwKey;
  909. Info.m_bActive = TRUE;
  910. try
  911. {
  912. m_mapInstructions[pInst] = Info;
  913. }
  914. catch(CX_MemoryException)
  915. {
  916. return WBEM_E_OUT_OF_MEMORY;
  917. }
  918. pInst->AddRef();
  919. //
  920. // Postpone the first execution of the query.
  921. // 1. Execution may not be done here, because the namespace is
  922. // locked
  923. // 2. Execution may not be done asynchronously, because we
  924. // must get a baseline reading before returning to the
  925. // client.
  926. //
  927. CPostponedList* pList = GetCurrentPostponedList();
  928. _DBG_ASSERT( pList != NULL );
  929. CPostponedQuery* pReq = new CPostponedQuery( pInst );
  930. if ( pReq && pList )
  931. {
  932. hr = pList->AddRequest( m_pNamespace, pReq );
  933. if ( FAILED(hr) )
  934. {
  935. delete pReq;
  936. }
  937. }
  938. else
  939. {
  940. hr = WBEM_E_OUT_OF_MEMORY;
  941. delete pReq;
  942. }
  943. if ( FAILED(hr) )
  944. {
  945. pInst->Release();
  946. m_mapInstructions.erase( pInst );
  947. }
  948. return hr;
  949. }
  950. HRESULT CPoller::DeactivateFilter(CEventFilter* pDest)
  951. {
  952. CInCritSec ics(&m_cs);
  953. DWORD_PTR dwKey = (DWORD_PTR)pDest;
  954. // Remove it from the map
  955. // ======================
  956. CInstructionMap::iterator it = m_mapInstructions.begin();
  957. DWORD nItems = 0;
  958. while(it != m_mapInstructions.end())
  959. {
  960. if(it->second.m_dwFilterId == dwKey)
  961. {
  962. CBasePollingInstruction* pInst = it->first;
  963. //
  964. // First, cancel the instruction so that if it is executing, it will
  965. // abort at the earliest convenience
  966. //
  967. pInst->Cancel();
  968. //
  969. // Then, deactivate the timer. This will block until the
  970. // instruction has finished executing, if it is currently doing so
  971. //
  972. pInst->DeleteTimer();
  973. //
  974. // Now we are safe --- release the instruction.
  975. //
  976. it = m_mapInstructions.erase(it);
  977. pInst->Release();
  978. nItems++;
  979. }
  980. else it++;
  981. }
  982. // Release our quotas if needed.
  983. if (nItems)
  984. g_quotas.DecrementQuotaIndex(ESSQ_POLLING_INSTRUCTIONS, pDest, nItems);
  985. return WBEM_S_NO_ERROR;
  986. }
  987. HRESULT CPoller::ListNonProvidedClasses(IN CClassInformation* pInfo,
  988. IN DWORD dwDesiredMask,
  989. OUT CClassInfoArray& aNonProvided)
  990. {
  991. HRESULT hres;
  992. aNonProvided.Clear();
  993. // Get the class itself
  994. // ====================
  995. IWbemServices* pNamespace;
  996. hres = m_pNamespace->GetNamespacePointer(&pNamespace);
  997. if(FAILED(hres))
  998. return hres;
  999. CReleaseMe rm0(pNamespace);
  1000. IWbemClassObject* pClass = NULL;
  1001. hres = pNamespace->GetObject( CWbemBSTR( pInfo->m_wszClassName ), 0,
  1002. GetCurrentEssContext(), &pClass, NULL);
  1003. if(FAILED(hres))
  1004. return hres;
  1005. CReleaseMe rm1(pClass);
  1006. if(IsClassDynamic(pClass))
  1007. {
  1008. AddDynamicClass(pClass, dwDesiredMask, aNonProvided);
  1009. return WBEM_S_NO_ERROR;
  1010. }
  1011. // Enumerate all its descendants
  1012. // =============================
  1013. IEnumWbemClassObject* pEnum;
  1014. hres = pNamespace->CreateClassEnum( CWbemBSTR( pInfo->m_wszClassName ),
  1015. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY |
  1016. ((pInfo->m_bIncludeChildren)?WBEM_FLAG_DEEP:WBEM_FLAG_SHALLOW),
  1017. GetCurrentEssContext(), &pEnum);
  1018. if(FAILED(hres)) return hres;
  1019. CReleaseMe rm3(pEnum);
  1020. IWbemClassObject* pChild = NULL;
  1021. DWORD dwNumRet;
  1022. while(SUCCEEDED(pEnum->Next(INFINITE, 1, &pChild, &dwNumRet)) && dwNumRet > 0)
  1023. {
  1024. // Check if this one is dynamic
  1025. // ============================
  1026. if(IsClassDynamic(pChild))
  1027. {
  1028. AddDynamicClass(pChild, dwDesiredMask, aNonProvided);
  1029. }
  1030. pChild->Release();
  1031. pChild = NULL;
  1032. }
  1033. return WBEM_S_NO_ERROR;
  1034. }
  1035. BOOL CPoller::AddDynamicClass(IWbemClassObject* pClass, DWORD dwDesiredMask,
  1036. OUT CClassInfoArray& aNonProvided)
  1037. {
  1038. // Check to see if all desired events are provided
  1039. // ===============================================
  1040. DWORD dwProvidedMask = m_pNamespace->GetProvidedEventMask(pClass);
  1041. DWORD dwRemainingMask = ((~dwProvidedMask) & dwDesiredMask);
  1042. if(dwRemainingMask)
  1043. {
  1044. // Add it to the array of classes to poll
  1045. // ======================================
  1046. CClassInformation* pNewInfo = _new CClassInformation;
  1047. if(pNewInfo == NULL)
  1048. return WBEM_E_OUT_OF_MEMORY;
  1049. _variant_t v;
  1050. if (FAILED(pClass->Get(L"__CLASS", 0, &v, NULL, NULL)))
  1051. {
  1052. delete pNewInfo;
  1053. return WBEM_E_OUT_OF_MEMORY;
  1054. }
  1055. pNewInfo->m_wszClassName = CloneWstr(V_BSTR(&v));
  1056. if(pNewInfo->m_wszClassName == NULL)
  1057. {
  1058. delete pNewInfo;
  1059. return WBEM_E_OUT_OF_MEMORY;
  1060. }
  1061. pNewInfo->m_bIncludeChildren = FALSE;
  1062. pNewInfo->m_dwEventMask = dwRemainingMask;
  1063. pNewInfo->m_pClass = pClass;
  1064. pClass->AddRef();
  1065. if(!aNonProvided.AddClass(pNewInfo))
  1066. {
  1067. delete pNewInfo;
  1068. return WBEM_E_OUT_OF_MEMORY;
  1069. }
  1070. return TRUE;
  1071. }
  1072. return FALSE;
  1073. }
  1074. BOOL CPoller::IsClassDynamic(IWbemClassObject* pClass)
  1075. {
  1076. HRESULT hres;
  1077. IWbemQualifierSet* pSet;
  1078. hres = pClass->GetQualifierSet(&pSet);
  1079. if(FAILED(hres))
  1080. return TRUE;
  1081. VARIANT v;
  1082. VariantInit(&v);
  1083. hres = pSet->Get(L"dynamic", 0, &v, NULL);
  1084. pSet->Release();
  1085. if(FAILED(hres)) return FALSE;
  1086. BOOL bRes = V_BOOL(&v);
  1087. VariantClear(&v);
  1088. return bRes;
  1089. }
  1090. HRESULT CPoller::VirtuallyStopPolling()
  1091. {
  1092. CInCritSec ics(&m_cs);
  1093. // Mark all polling instructions in the map with the key of 0xFFFFFFFF
  1094. // This will not stop them from working, but will separate them from the
  1095. // new ones.
  1096. // =====================================================================
  1097. for(CInstructionMap::iterator it = m_mapInstructions.begin();
  1098. it != m_mapInstructions.end(); it++)
  1099. {
  1100. it->second.m_bActive = FALSE;
  1101. }
  1102. m_bInResync = TRUE;
  1103. return WBEM_S_NO_ERROR;
  1104. }
  1105. HRESULT CPoller::CancelUnnecessaryPolling()
  1106. {
  1107. CInCritSec ics(&m_cs);
  1108. // Remove it from the map
  1109. // ======================
  1110. CInstructionMap::iterator it = m_mapInstructions.begin();
  1111. while(it != m_mapInstructions.end())
  1112. {
  1113. if( !it->second.m_bActive )
  1114. {
  1115. CBasePollingInstruction* pInst = it->first;
  1116. //
  1117. // First, cancel the instruction so that if it is executing, it will
  1118. // abort at the earliest convenience
  1119. //
  1120. pInst->Cancel();
  1121. //
  1122. // Then, deactivate the timer. This will block until the
  1123. // instruction has finished executing, if it is currently doing so
  1124. //
  1125. pInst->DeleteTimer();
  1126. //
  1127. // Now we are safe --- release the instruction.
  1128. //
  1129. it = m_mapInstructions.erase(it);
  1130. pInst->Release();
  1131. }
  1132. else it++;
  1133. }
  1134. m_bInResync = FALSE;
  1135. return WBEM_S_NO_ERROR;
  1136. }
  1137. void CPoller::DumpStatistics(FILE* f, long lFlags)
  1138. {
  1139. fprintf(f, "%d polling instructions\n", m_mapInstructions.size());
  1140. }