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.

616 lines
15 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. DTEvntSk.cpp
  5. Abstract:
  6. This module contains implementation of CPTEventSink.
  7. Author:
  8. vlade Nov 1999
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. //
  13. // a helper function that releases the resources allocated inside event info
  14. //
  15. HRESULT FreeEventInfo( MSP_EVENT_INFO * pEvent )
  16. {
  17. LOG((MSP_TRACE, "FreeEventInfo - enter"));
  18. switch ( pEvent->Event )
  19. {
  20. case ME_ADDRESS_EVENT:
  21. if (NULL != pEvent->MSP_ADDRESS_EVENT_INFO.pTerminal)
  22. {
  23. (pEvent->MSP_ADDRESS_EVENT_INFO.pTerminal)->Release();
  24. }
  25. break;
  26. case ME_CALL_EVENT:
  27. if (NULL != pEvent->MSP_CALL_EVENT_INFO.pTerminal)
  28. {
  29. (pEvent->MSP_CALL_EVENT_INFO.pTerminal)->Release();
  30. }
  31. if (NULL != pEvent->MSP_CALL_EVENT_INFO.pStream)
  32. {
  33. (pEvent->MSP_CALL_EVENT_INFO.pStream)->Release();
  34. }
  35. break;
  36. case ME_TSP_DATA:
  37. break;
  38. case ME_PRIVATE_EVENT:
  39. if ( NULL != pEvent->MSP_PRIVATE_EVENT_INFO.pEvent )
  40. {
  41. (pEvent->MSP_PRIVATE_EVENT_INFO.pEvent)->Release();
  42. }
  43. break;
  44. case ME_FILE_TERMINAL_EVENT:
  45. if( NULL != pEvent->MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal)
  46. {
  47. (pEvent->MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal)->Release();
  48. pEvent->MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal = NULL;
  49. }
  50. if( NULL != pEvent->MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack )
  51. {
  52. (pEvent->MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack)->Release();
  53. pEvent->MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack = NULL;
  54. }
  55. break;
  56. case ME_ASR_TERMINAL_EVENT:
  57. if( NULL != pEvent->MSP_ASR_TERMINAL_EVENT_INFO.pASRTerminal)
  58. {
  59. (pEvent->MSP_ASR_TERMINAL_EVENT_INFO.pASRTerminal)->Release();
  60. }
  61. break;
  62. case ME_TTS_TERMINAL_EVENT:
  63. if( NULL != pEvent->MSP_TTS_TERMINAL_EVENT_INFO.pTTSTerminal)
  64. {
  65. (pEvent->MSP_TTS_TERMINAL_EVENT_INFO.pTTSTerminal)->Release();
  66. }
  67. break;
  68. case ME_TONE_TERMINAL_EVENT:
  69. if( NULL != pEvent->MSP_TONE_TERMINAL_EVENT_INFO.pToneTerminal)
  70. {
  71. (pEvent->MSP_TONE_TERMINAL_EVENT_INFO.pToneTerminal)->Release();
  72. }
  73. break;
  74. default:
  75. break;
  76. }
  77. LOG((MSP_TRACE, "FreeEventInfo - finished"));
  78. return S_OK;
  79. }
  80. CPTEventSink::CPTEventSink() :
  81. m_pMSPStream(NULL)
  82. {
  83. LOG((MSP_TRACE, "CPTEventSink::CPTEventSink enter"));
  84. LOG((MSP_TRACE, "CPTEventSink::CPTEventSink exit"));
  85. }
  86. CPTEventSink::~CPTEventSink()
  87. {
  88. LOG((MSP_TRACE, "CPTEventSink::~CPTEventSink enter"));
  89. LOG((MSP_TRACE, "CPTEventSink::~CPTEventSink exit"));
  90. };
  91. // --- ITPluggableTerminalEventSnk ---
  92. /*++
  93. FireEvent
  94. Parameters:
  95. IN MSPEVENTITEM * pEventItem pointer to the structure that describes the
  96. event. all the pointers contained in the structure must be addreffed by
  97. the caller, and then released by the caller if FireEvent fails
  98. FireEvent makes a (shallow) copy of the structure, so the caller can
  99. delete the structure when the function returns
  100. Returns:
  101. S_OK - every thing was OK
  102. E_FAIL & other - something was wrong
  103. Description:
  104. This method is called by the dynamic terminals to
  105. signal a new event
  106. --*/
  107. STDMETHODIMP CPTEventSink::FireEvent(
  108. IN const MSP_EVENT_INFO * pEventInfo
  109. )
  110. {
  111. LOG((MSP_TRACE, "CPTEventSink::FireEvent enter"));
  112. //
  113. // make sure we got a good mspeventitem structure
  114. //
  115. if( MSPB_IsBadWritePtr( (void*)pEventInfo, sizeof( MSP_EVENT_INFO )))
  116. {
  117. LOG((MSP_ERROR, "CPTEventSink::FireEvent -"
  118. "pEventItem is bad, returns E_POINTER"));
  119. return E_POINTER;
  120. }
  121. //
  122. // Create an MSPEVENTITEM
  123. //
  124. MSPEVENTITEM *pEventItem = AllocateEventItem();
  125. if (NULL == pEventItem)
  126. {
  127. LOG((MSP_ERROR, "CPTEventSink::FireEvent -"
  128. "failed to create MSPEVENTITEM. returning E_OUTOFMEMORY "));
  129. return E_OUTOFMEMORY;
  130. }
  131. //
  132. // make a shallow copy of the structure
  133. //
  134. pEventItem->MSPEventInfo = *pEventInfo;
  135. Lock();
  136. HRESULT hr = E_FAIL;
  137. if (NULL != m_pMSPStream)
  138. {
  139. //
  140. // nicely ask stream to process our event
  141. //
  142. LOG((MSP_TRACE, "CPTEventSink::FireEvent - passing event [%p] to the stream", pEventItem));
  143. AsyncEventStruct *pAsyncEvent = new AsyncEventStruct;
  144. if (NULL == pAsyncEvent)
  145. {
  146. LOG((MSP_ERROR,
  147. "CPTEventSink::FireEvent - failed to allocate memory for AsyncEventStruct"));
  148. hr = E_OUTOFMEMORY;
  149. }
  150. else
  151. {
  152. //
  153. // stuff the structure with the addref'fed stream on which the
  154. // event will be fired and the actual event to fire
  155. //
  156. ULONG ulRC = m_pMSPStream->AddRef();
  157. if (1 == ulRC)
  158. {
  159. //
  160. // this is a workaround for a timing window: the stream could
  161. // be in its desctructor while we are doing the addref. this
  162. // condition is very-vary rare, as the timing window is very
  163. // narrow.
  164. //
  165. // the good thing is that stream destructor will not finish
  166. // while we are here, because it will try to get event sink's
  167. // critical section in its call to SetSinkStream() to set our
  168. // stream pointer to NULL.
  169. //
  170. // so if we detect that the refcount after our addref is 1,
  171. // that would mean that the stream is in (or is about to start
  172. // executing its desctructor). in which case we should do
  173. // nothing.
  174. //
  175. // cleanup and return a failure.
  176. //
  177. Unlock();
  178. LOG((MSP_ERROR,
  179. "CPTEventSink::FireEvent - stream is going away"));
  180. delete pAsyncEvent;
  181. pAsyncEvent = NULL;
  182. FreeEventItem(pEventItem);
  183. pEventItem = NULL;
  184. return TAPI_E_INVALIDSTREAM;
  185. }
  186. pAsyncEvent->pMSPStream = m_pMSPStream;
  187. pAsyncEvent->pEventItem = pEventItem;
  188. //
  189. // now use thread pool api to schedule the event for future async
  190. // processing
  191. //
  192. BOOL bQueueSuccess = QueueUserWorkItem(
  193. CPTEventSink::FireEventCallBack,
  194. (void *)pAsyncEvent,
  195. WT_EXECUTEDEFAULT);
  196. if (!bQueueSuccess)
  197. {
  198. DWORD dwLastError = GetLastError();
  199. LOG((MSP_ERROR,
  200. "CPTEventSink::FireEvent - QueueUserWorkItem failed. LastError = %ld", dwLastError));
  201. //
  202. // undo the addref we did on the stream object. the event will
  203. // be freed later
  204. //
  205. m_pMSPStream->Release();
  206. //
  207. // the event was not enqueued. delete now.
  208. //
  209. delete pAsyncEvent;
  210. pAsyncEvent = NULL;
  211. //
  212. // map the code and bail out
  213. //
  214. hr = HRESULT_FROM_WIN32(dwLastError);
  215. }
  216. else
  217. {
  218. //
  219. // log the event we have submitted, so we can match submission
  220. // with processing from the log
  221. //
  222. LOG((MSP_TRACE,
  223. "CPTEventSink::FireEvent - submitted event [%p]", pAsyncEvent));
  224. hr = S_OK;
  225. } // async event structure submitted
  226. } // async event structure allocated
  227. } // msp stream exists
  228. else
  229. {
  230. hr = TAPI_E_INVALIDSTREAM;
  231. LOG((MSP_ERROR,
  232. "CPTEventSink::FireEvent - stream pointer is NULL"));
  233. }
  234. Unlock();
  235. //
  236. // if we don't have a stream, or if the stream refused to process the
  237. // event, cleanup and return an error
  238. //
  239. if (FAILED(hr))
  240. {
  241. LOG((MSP_ERROR, "CPTEventSink::FireEvent - call to HandleStreamEvent failed. hr = 0x%08x", hr));
  242. FreeEventItem(pEventItem);
  243. return hr;
  244. }
  245. LOG((MSP_TRACE, "CPTEventSink::FireEvent - exit"));
  246. return S_OK;
  247. }
  248. /////////////////////////////////////////////////////////////////////////////
  249. //
  250. // CPTEventSink::FireEventCallBack
  251. //
  252. // the callback function that is called by thread pool api to asyncronously to
  253. // process events fired by the terminals.
  254. //
  255. // the argument should point to the structure that contains the pointer to the
  256. // stream on which to fire the event and the pointer to the event to fire.
  257. //
  258. // the dll is guaranteed to not go away, since the structure passed in holds a
  259. // reference to the stream object on which to process the event
  260. //
  261. // static
  262. DWORD WINAPI CPTEventSink::FireEventCallBack(LPVOID lpParameter)
  263. {
  264. LOG((MSP_TRACE, "CPTEventSink::FireEventCallBack - enter. Argument [%p]",
  265. lpParameter));
  266. AsyncEventStruct *pEventStruct = (AsyncEventStruct *)lpParameter;
  267. //
  268. // make sure the structure is valid
  269. //
  270. if (IsBadReadPtr(pEventStruct, sizeof(AsyncEventStruct)))
  271. {
  272. //
  273. // complain and exit. should not happen, unless there is a problem in
  274. // thread pool api or memory corruption
  275. //
  276. LOG((MSP_ERROR,
  277. "CPTEventSink::FireEventCallBack - Argument does not point to a valid AsyncEventStruct"));
  278. return FALSE;
  279. }
  280. BOOL bBadDataPassedIn = FALSE;
  281. //
  282. // the structure contains an addref'fed stream pointer. extract it and
  283. // make sure it is still valid
  284. //
  285. CMSPStream *pMSPStream = pEventStruct->pMSPStream;
  286. if (IsBadReadPtr(pMSPStream, sizeof(CMSPStream)))
  287. {
  288. //
  289. // should not happen, unless there is a problem in thread pool api or
  290. // memory corruption, or someone is over-releasing the stream object
  291. //
  292. LOG((MSP_ERROR,
  293. "CPTEventSink::FireEventCallBack - stream pointer is bad"));
  294. pMSPStream = NULL;
  295. bBadDataPassedIn = TRUE;
  296. }
  297. //
  298. // the structure contains the event that we are tryint to fire.
  299. // make sure the event we are about to fire is good.
  300. //
  301. MSPEVENTITEM *pEventItem = pEventStruct->pEventItem;
  302. if (IsBadReadPtr(pEventItem, sizeof(MSPEVENTITEM)))
  303. {
  304. //
  305. // should not happen, unless there is a problem in thread pool api or
  306. // memory corruption, or we didn't check success of allocation when we
  307. // created the event (which we did!)
  308. //
  309. LOG((MSP_ERROR,
  310. "CPTEventSink::FireEventCallBack - event is bad"));
  311. pEventItem = NULL;
  312. bBadDataPassedIn = TRUE;
  313. }
  314. //
  315. // bad stream or event structure?
  316. //
  317. if (bBadDataPassedIn)
  318. {
  319. //
  320. // release the event if it was good.
  321. //
  322. if ( NULL != pEventItem)
  323. {
  324. FreeEventItem(pEventItem);
  325. pEventItem = NULL;
  326. }
  327. //
  328. // release the stream if it was good.
  329. //
  330. if (NULL != pMSPStream)
  331. {
  332. pMSPStream->Release();
  333. pMSPStream = NULL;
  334. }
  335. //
  336. // no need to keep the event structure itself, delete it
  337. //
  338. delete pEventStruct;
  339. pEventStruct = NULL;
  340. return FALSE;
  341. }
  342. //
  343. // we have both the stream and the event, fire the event on the stream
  344. //
  345. HRESULT hr = pMSPStream->HandleSinkEvent(pEventItem);
  346. //
  347. // if HandleSinkEvent succeeded, pEventItem will be released by whoever
  348. // will handle the event, otherwise we need to release eventitem here
  349. //
  350. if (FAILED(hr))
  351. {
  352. LOG((MSP_ERROR,
  353. "CPTEventSink::FireEventCallBack - HandleSinkEvent not called or failed. hr = %lx",
  354. hr));
  355. //
  356. // need to free all the resources held by event info
  357. //
  358. FreeEventInfo(&(pEventItem->MSPEventInfo));
  359. FreeEventItem(pEventItem);
  360. pEventItem = NULL;
  361. }
  362. //
  363. // release the stream pointer that is a part of the structure --
  364. // we don't want any reference leaks.
  365. //
  366. //
  367. // note that the dll may go away at this point (if we are holding the last
  368. // reference to the last object from the dll)
  369. //
  370. pMSPStream->Release();
  371. pMSPStream = NULL;
  372. //
  373. // at this point we release the stream pointer and either submitted the
  374. // event or freed it. we no longer need the event structure.
  375. //
  376. delete pEventStruct;
  377. pEventStruct = NULL;
  378. LOG((MSP_(hr), "CPTEventSink::FireEventCallBack - exit. hr = %lx", hr));
  379. return SUCCEEDED(hr);
  380. }
  381. /*++
  382. SetSinkStream
  383. Parameters:
  384. CMSPStream *pStream
  385. the stream that will be processing our events, or NULL when no stream is
  386. available to process our events
  387. Returns:
  388. S_OK -
  389. Description:
  390. this method is called by the stream that is going to process our events
  391. when the stream is going away and is no longer available to process our
  392. messages, it will call SetSinkStream with NULL.
  393. --*/
  394. HRESULT CPTEventSink::SetSinkStream( CMSPStream *pStream )
  395. {
  396. LOG((MSP_TRACE, "CPTEventSink::SetSinkStream - enter"));
  397. Lock();
  398. LOG((MSP_TRACE,
  399. "CPTEventSink::SetSinkStream - replacing sink stream [%p] with [%p]",
  400. m_pMSPStream, pStream));
  401. //
  402. // we don't keep a reference to the stream -- the stream keeps a reference
  403. // to us. when the stream goes away, it will let us know.
  404. //
  405. m_pMSPStream = pStream;
  406. Unlock();
  407. LOG((MSP_TRACE, "CPTEventSink::SetSinkStream - exit"));
  408. return S_OK;
  409. }