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.

590 lines
15 KiB

  1. //******************************************************************************
  2. //
  3. // QSINK.CPP
  4. //
  5. // Copyright (C) 1996-1999 Microsoft Corporation
  6. //
  7. //******************************************************************************
  8. #include "precomp.h"
  9. #include <stdio.h>
  10. #include <genutils.h>
  11. #include <cominit.h>
  12. #include "ess.h"
  13. #include "evsink.h"
  14. #include "delivrec.h"
  15. #define IN_SPIN_LOCK CInCritSec
  16. #define MAX_EVENT_DELIVERY_SIZE 10000000
  17. #define SLOWDOWN_DROP_LIMIT 1000
  18. #define DELIVER_SPIN_COUNT 1000
  19. /*****************************************************************************
  20. CQueueingEventSink
  21. ******************************************************************************/
  22. CQueueingEventSink::CQueueingEventSink(CEssNamespace* pNamespace)
  23. : m_pNamespace(pNamespace), m_bDelivering(FALSE), m_dwTotalSize(0),
  24. m_dwMaxSize(0xFFFFFFFF), m_wszName(NULL), m_bRecovering(FALSE),
  25. m_hRecoveryComplete(NULL), m_hrRecovery(S_OK)
  26. {
  27. m_pNamespace->AddRef();
  28. m_pNamespace->AddCache();
  29. }
  30. CQueueingEventSink::~CQueueingEventSink()
  31. {
  32. if ( m_hRecoveryComplete != NULL )
  33. {
  34. CloseHandle( m_hRecoveryComplete );
  35. }
  36. delete m_wszName;
  37. m_pNamespace->RemoveCache();
  38. m_pNamespace->Release();
  39. }
  40. HRESULT CQueueingEventSink::SetName( LPCWSTR wszName )
  41. {
  42. if ( m_wszName != NULL )
  43. {
  44. return WBEM_E_CRITICAL_ERROR;
  45. }
  46. m_wszName = new WCHAR[wcslen(wszName)+1];
  47. if ( m_wszName == NULL )
  48. {
  49. return WBEM_E_OUT_OF_MEMORY;
  50. }
  51. StringCchCopyW( m_wszName, wcslen(wszName)+1, wszName );
  52. return WBEM_S_NO_ERROR;
  53. }
  54. STDMETHODIMP CQueueingEventSink::SecureIndicate( long lNumEvents,
  55. IWbemEvent** apEvents,
  56. BOOL bMaintainSecurity,
  57. BOOL bSlowDown,
  58. DWORD dwQoS,
  59. CEventContext* pContext)
  60. {
  61. // BUGBUG: context. levn: no security implications at this level --- we
  62. // are past the filter
  63. HRESULT hres;
  64. DWORD dwSleep = 0;
  65. // If security needs to be maintained, record the calling security
  66. // context
  67. // ===============================================================
  68. IWbemCallSecurity* pSecurity = NULL;
  69. if(bMaintainSecurity && IsNT())
  70. {
  71. pSecurity = CWbemCallSecurity::CreateInst();
  72. if (pSecurity == 0)
  73. return WBEM_E_OUT_OF_MEMORY;
  74. hres = pSecurity->CloneThreadContext(FALSE);
  75. if(FAILED(hres))
  76. {
  77. pSecurity->Release();
  78. return hres;
  79. }
  80. }
  81. CReleaseMe rmpSecurity( pSecurity );
  82. HRESULT hr;
  83. BOOL bSchedule = FALSE;
  84. for(int i = 0; i < lNumEvents; i++)
  85. {
  86. CWbemPtr<CDeliveryRecord> pRecord;
  87. //
  88. // TODO: Fix this so that we put multiple events in the record.
  89. //
  90. hr = GetDeliveryRecord( 1,
  91. &apEvents[i],
  92. dwQoS,
  93. pContext,
  94. pSecurity,
  95. &pRecord );
  96. if ( FAILED(hr) )
  97. {
  98. ERRORTRACE((LOG_ESS, "Couldn't create delivery record for %S "
  99. " sink. HR = 0x%x\n", m_wszName, hr ));
  100. ReportQosFailure( apEvents[i], hr );
  101. continue;
  102. }
  103. DWORD dwThisSleep;
  104. BOOL bFirst;
  105. if( !AddRecord( pRecord, bSlowDown, &dwThisSleep, &bFirst) )
  106. {
  107. //
  108. // make sure that we give the record a chance to perform any post
  109. // deliver actions before getting rid of it.
  110. //
  111. pRecord->PostDeliverAction( NULL, S_OK );
  112. return WBEM_E_OUT_OF_MEMORY;
  113. }
  114. dwSleep += dwThisSleep;
  115. if(bFirst)
  116. bSchedule = TRUE;
  117. }
  118. if(bSchedule)
  119. {
  120. // DeliverAll();
  121. // TRACE((LOG_ESS, "Scheduling delivery!!\n"));
  122. hres = m_pNamespace->ScheduleDelivery(this);
  123. }
  124. else
  125. {
  126. // TRACE((LOG_ESS, "NOT Scheduling delivery!!\n"));
  127. hres = WBEM_S_FALSE;
  128. }
  129. if(dwSleep && bSlowDown)
  130. m_pNamespace->AddSleepCharge(dwSleep);
  131. return hres;
  132. }
  133. BOOL CQueueingEventSink::AddRecord( CDeliveryRecord* pRecord,
  134. BOOL bSlowDown,
  135. DWORD* pdwSleep,
  136. BOOL* pbFirst )
  137. {
  138. // Inform the system of the additional space in the queue
  139. // ======================================================
  140. DWORD dwRecordSize = pRecord->GetTotalBytes();
  141. pRecord->AddToCache( m_pNamespace, m_dwTotalSize, pdwSleep );
  142. BOOL bDrop = FALSE;
  143. // Check if the sleep is such as to cause us to drop the event
  144. // ===========================================================
  145. if(!bSlowDown && *pdwSleep > SLOWDOWN_DROP_LIMIT)
  146. {
  147. bDrop = TRUE;
  148. }
  149. else
  150. {
  151. // Check if our queue size is so large as to cause us to drop
  152. // ==============================================================
  153. if(m_dwTotalSize + dwRecordSize > m_dwMaxSize)
  154. bDrop = TRUE;
  155. }
  156. if( bDrop )
  157. {
  158. //
  159. // Report that we're dropping the events. Call for each event.
  160. //
  161. IWbemClassObject** apEvents = pRecord->GetEvents();
  162. for( ULONG i=0; i < pRecord->GetNumEvents(); i++ )
  163. {
  164. ReportQueueOverflow( apEvents[i], m_dwTotalSize + dwRecordSize );
  165. }
  166. *pdwSleep = 0;
  167. *pbFirst = FALSE;
  168. }
  169. else
  170. {
  171. IN_SPIN_LOCK isl(&m_sl);
  172. *pbFirst = (m_qpEvents.GetQueueSize() == 0) && !m_bDelivering;
  173. m_dwTotalSize += dwRecordSize;
  174. if(!m_qpEvents.Enqueue(pRecord))
  175. {
  176. *pdwSleep = 0;
  177. return FALSE;
  178. }
  179. pRecord->AddRef();
  180. }
  181. return TRUE;
  182. }
  183. HRESULT CQueueingEventSink::DeliverAll()
  184. {
  185. HRESULT hr = WBEM_S_NO_ERROR;
  186. BOOL bSomeLeft = TRUE;
  187. while( bSomeLeft )
  188. {
  189. try
  190. {
  191. {
  192. IN_SPIN_LOCK ics(&m_sl);
  193. m_bDelivering = TRUE;
  194. }
  195. hr = DeliverSome( );
  196. }
  197. catch( CX_MemoryException )
  198. {
  199. hr = WBEM_E_OUT_OF_MEMORY;
  200. }
  201. catch ( ... )
  202. {
  203. hr = WBEM_E_FAILED;
  204. }
  205. {
  206. IN_SPIN_LOCK ics(&m_sl);
  207. m_bDelivering = FALSE;
  208. if ( SUCCEEDED( hr ) )
  209. {
  210. bSomeLeft = (m_qpEvents.GetQueueSize() != 0);
  211. }
  212. else
  213. {
  214. m_qpEvents.Clear();
  215. bSomeLeft = FALSE;
  216. }
  217. }
  218. }
  219. return hr;
  220. }
  221. void CQueueingEventSink::ClearAll()
  222. {
  223. IN_SPIN_LOCK isl(&m_sl);
  224. m_qpEvents.Clear();
  225. }
  226. #pragma optimize("", off)
  227. void CQueueingEventSink::WaitABit()
  228. {
  229. SwitchToThread();
  230. /*
  231. int nCount = 0;
  232. while(m_qpEvents.GetQueueSize() == 0 && nCount++ < DELIVER_SPIN_COUNT);
  233. */
  234. }
  235. #pragma optimize("", on)
  236. HRESULT CQueueingEventSink::DeliverSome( )
  237. {
  238. // Retrieve records until maximum size is reached and while the same
  239. // security context is used for all
  240. // ==================================================================
  241. CTempArray<CDeliveryRecord*> apRecords;
  242. m_sl.Enter(); // CANNOT USE SCOPE BECAUSE CTempArray uses _alloca
  243. DWORD dwMaxRecords = m_qpEvents.GetQueueSize();
  244. m_sl.Leave();
  245. if(!INIT_TEMP_ARRAY(apRecords, dwMaxRecords))
  246. {
  247. return WBEM_E_OUT_OF_MEMORY;
  248. }
  249. CDeliveryRecord* pEventRec;
  250. DWORD dwDeliverySize = 0;
  251. DWORD dwTotalEvents = 0;
  252. int cRecords = 0;
  253. LUID luidBatch;
  254. IWbemCallSecurity* pBatchSecurity = NULL;
  255. m_sl.Enter();
  256. while( dwDeliverySize < GetMaxDeliverySize() &&
  257. cRecords < dwMaxRecords &&
  258. (pEventRec = m_qpEvents.Dequeue()) != NULL )
  259. {
  260. // Compare it to the last context
  261. // ==============================
  262. m_sl.Leave();
  263. if( dwDeliverySize > 0 )
  264. {
  265. if(!DoesRecordFitBatch(pEventRec, pBatchSecurity, luidBatch))
  266. {
  267. // Put it back and that's it for the batch
  268. // =======================================
  269. IN_SPIN_LOCK ics(&m_sl);
  270. m_qpEvents.Requeue(pEventRec);
  271. m_sl.Enter();
  272. break;
  273. }
  274. }
  275. else
  276. {
  277. // First --- record luid
  278. // =====================
  279. pBatchSecurity = pEventRec->GetCallSecurity();
  280. if( pBatchSecurity )
  281. {
  282. pBatchSecurity->AddRef();
  283. pBatchSecurity->GetAuthenticationId( luidBatch );
  284. }
  285. }
  286. apRecords[cRecords++] = pEventRec;
  287. dwTotalEvents += pEventRec->GetNumEvents();
  288. // Matched batch parameters --- add it to the batch
  289. // ================================================
  290. DWORD dwRecordSize = pEventRec->GetTotalBytes();
  291. m_dwTotalSize -= dwRecordSize;
  292. dwDeliverySize += dwRecordSize;
  293. //
  294. // Remove this size from the total of events held
  295. //
  296. m_sl.Enter();
  297. }
  298. m_sl.Leave();
  299. //
  300. // we've now got one or more delivery records to handle.
  301. //
  302. //
  303. // we now need to initialize the event array that we're going to indicate
  304. // to the client.
  305. //
  306. CTempArray<IWbemClassObject*> apEvents;
  307. if( !INIT_TEMP_ARRAY( apEvents, dwTotalEvents ))
  308. {
  309. return WBEM_E_OUT_OF_MEMORY;
  310. }
  311. //
  312. // go through the delivery records and add their events to the
  313. // events to deliver. Also perform any PreDeliverAction on the
  314. // record.
  315. //
  316. CWbemPtr<ITransaction> pTxn;
  317. HRESULT hr;
  318. int cEvents = 0;
  319. int i;
  320. for(i=0; i < cRecords; i++ )
  321. {
  322. //if ( apRecords[i]->RequiresTransaction() && pTxn == NULL )
  323. //{
  324. // TODO : XACT - aquire txn from DTC.
  325. //}
  326. hr = apRecords[i]->PreDeliverAction( pTxn );
  327. if ( FAILED(hr) )
  328. {
  329. //
  330. // TODO : handle error reporting here.
  331. //
  332. continue;
  333. }
  334. IWbemEvent** apRecordEvents = apRecords[i]->GetEvents();
  335. DWORD cRecordEvents = apRecords[i]->GetNumEvents();
  336. for( DWORD j=0; j < cRecordEvents; j++ )
  337. {
  338. apEvents[cEvents++] = apRecordEvents[j];
  339. }
  340. }
  341. // Actually Deliver
  342. // =======
  343. HRESULT hres = WBEM_S_NO_ERROR;
  344. if( dwDeliverySize > 0 )
  345. {
  346. //
  347. // Error returns are already logged in ActuallyDeliver
  348. // we do not need to return return value of DeliverEvents
  349. //
  350. hres = DeliverEvents( pBatchSecurity, cEvents, apEvents );
  351. }
  352. //
  353. // call postdeliveryaction on all the records. Then clean them up.
  354. //
  355. for(i=0; i < cRecords; i++ )
  356. {
  357. apRecords[i]->PostDeliverAction( pTxn, hres );
  358. apRecords[i]->Release();
  359. }
  360. // Release all of the events.
  361. // ================
  362. if( pBatchSecurity )
  363. {
  364. pBatchSecurity->Release();
  365. }
  366. // Check if we need to continue
  367. // ============================
  368. WaitABit();
  369. return WBEM_S_NO_ERROR;
  370. }
  371. HRESULT CQueueingEventSink::DeliverEvents(IWbemCallSecurity* pBatchSecurity,
  372. long lNumEvents, IWbemEvent** apEvents)
  373. {
  374. HRESULT hres = WBEM_S_NO_ERROR;
  375. IUnknown* pOldSec = NULL;
  376. if(pBatchSecurity)
  377. {
  378. hres = WbemCoSwitchCallContext(pBatchSecurity, &pOldSec);
  379. if(FAILED(hres))
  380. {
  381. // Unable to set security --- cannot deliver
  382. // =========================================
  383. return hres;
  384. }
  385. }
  386. if(SUCCEEDED(hres))
  387. {
  388. // BUGBUG: propagate context. levn: no security implications at this
  389. // point --- we are past the filter
  390. hres = ActuallyDeliver(lNumEvents, apEvents, (pBatchSecurity != NULL),
  391. NULL);
  392. }
  393. if(pBatchSecurity)
  394. {
  395. IUnknown* pTemp;
  396. HRESULT hr = WbemCoSwitchCallContext(pOldSec, &pTemp);
  397. if ( FAILED( hr ) && SUCCEEDED( hres ) )
  398. {
  399. return hr;
  400. }
  401. }
  402. return hres;
  403. }
  404. BOOL CQueueingEventSink::DoesRecordFitBatch( CDeliveryRecord* pEventRec,
  405. IWbemCallSecurity* pBatchSecurity,
  406. LUID luidBatch )
  407. {
  408. IWbemCallSecurity* pEventSec = pEventRec->GetCallSecurity();
  409. if( pEventSec != NULL || pBatchSecurity != NULL )
  410. {
  411. if( pEventSec == NULL || pBatchSecurity == NULL )
  412. {
  413. // Definite mistatch --- one NULL, one not
  414. // =======================================
  415. return FALSE;
  416. }
  417. else
  418. {
  419. LUID luidThis;
  420. pEventSec->GetAuthenticationId(luidThis);
  421. if( luidThis.LowPart != luidBatch.LowPart ||
  422. luidThis.HighPart != luidBatch.HighPart )
  423. {
  424. return FALSE;
  425. }
  426. else
  427. {
  428. return TRUE;
  429. }
  430. }
  431. }
  432. else
  433. {
  434. return TRUE;
  435. }
  436. }
  437. DWORD CQueueingEventSink::GetMaxDeliverySize()
  438. {
  439. return MAX_EVENT_DELIVERY_SIZE;
  440. }
  441. HRESULT CQueueingEventSink::GetDeliveryRecord( ULONG cEvents,
  442. IWbemEvent** apEvents,
  443. DWORD dwQos,
  444. CEventContext* pContext,
  445. IWbemCallSecurity* pCallSec,
  446. CDeliveryRecord** ppRecord )
  447. {
  448. *ppRecord = NULL;
  449. CWbemPtr<CDeliveryRecord> pRecord;
  450. if ( dwQos == WMIMSG_FLAG_QOS_EXPRESS )
  451. {
  452. pRecord = new CExpressDeliveryRecord;
  453. if ( pRecord == NULL )
  454. {
  455. return WBEM_E_OUT_OF_MEMORY;
  456. }
  457. HRESULT hr = pRecord->Initialize( apEvents, cEvents, pCallSec );
  458. if ( FAILED(hr) )
  459. {
  460. return hr;
  461. }
  462. }
  463. pRecord->AddRef();
  464. *ppRecord = pRecord;
  465. return WBEM_S_NO_ERROR;
  466. }