Source code of Windows XP (NT5)
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.

455 lines
10 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. #include "precomp.h"
  8. #include <assert.h>
  9. #include <wbemcli.h>
  10. #include "msmqrecv.h"
  11. #include "msmqcomn.h"
  12. #define CALLFUNC(FUNC) (*m_Api.m_fp ## FUNC )
  13. /**************************************************************************
  14. CMsgMsmqReceiver
  15. ***************************************************************************/
  16. CMsgMsmqReceiver::CMsgMsmqReceiver( CLifeControl* pCtl )
  17. : CUnkBase<IWmiMessageReceiver,&IID_IWmiMessageReceiver>( pCtl ),
  18. m_pSvcId(NULL), m_hQueue(INVALID_HANDLE_VALUE), m_dwFlags(0)
  19. {
  20. }
  21. CMsgMsmqReceiver::~CMsgMsmqReceiver()
  22. {
  23. Close();
  24. }
  25. HRESULT CMsgMsmqReceiver::Close()
  26. {
  27. ENTER_API_CALL
  28. //
  29. // before removing the sink from the service, the receiver is
  30. // responsible for knocking the sink out its blocking calls on the
  31. // queue. This is done by closing the queue handle.
  32. //
  33. if ( m_hQueue != INVALID_HANDLE_VALUE )
  34. {
  35. CALLFUNC(MQCloseQueue)( m_hQueue );
  36. m_hQueue = INVALID_HANDLE_VALUE;
  37. }
  38. if ( m_pSvcId != NULL )
  39. {
  40. assert( m_pSvc != NULL );
  41. m_pSvc->Remove( m_pSvcId );
  42. m_pSvcId = NULL;
  43. }
  44. m_pSvc.Release();
  45. m_pHndlr.Release();
  46. return S_OK;
  47. EXIT_API_CALL
  48. }
  49. HRESULT CMsgMsmqReceiver::EnsureReceiver()
  50. {
  51. HRESULT hr;
  52. assert( m_pHndlr == NULL );
  53. assert( m_pSvc == NULL );
  54. assert( m_pSvcId == NULL );
  55. assert( m_hQueue == INVALID_QUEUE_HANDLE );
  56. //
  57. // obtain a pointer to the message service. The message service is a
  58. // singleton. This way, all receivers can locate and share the same
  59. // service. The receiver is going to hand its receiver sink to the
  60. // service.
  61. //
  62. hr = CoCreateInstance( CLSID_WmiMessageService,
  63. NULL,
  64. CLSCTX_INPROC,
  65. IID_IWmiMessageService,
  66. (void**)&m_pSvc );
  67. if ( FAILED(hr) )
  68. {
  69. return hr;
  70. }
  71. hr = EnsureMsmqService( m_Api );
  72. if ( FAILED(hr) )
  73. {
  74. return hr;
  75. }
  76. //
  77. // try to normalize the queue name.
  78. //
  79. WString wsFormat;
  80. hr = NormalizeQueueName( m_Api, m_wsEndpoint, wsFormat );
  81. if ( FAILED(hr) )
  82. {
  83. return hr;
  84. }
  85. //
  86. // try to open the queue
  87. //
  88. hr = CALLFUNC(MQOpenQueue)( wsFormat,
  89. MQ_RECEIVE_ACCESS,
  90. MQ_DENY_NONE,
  91. &m_hQueue );
  92. if ( FAILED(hr) )
  93. {
  94. return MqResToWmiRes( hr, WMIMSG_E_TARGETNOTFOUND );
  95. }
  96. hr = CMsgMsmqHandler::Create( m_Api,
  97. m_pRecv,
  98. m_hQueue,
  99. m_dwFlags,
  100. &m_pHndlr );
  101. if ( FAILED(hr) )
  102. {
  103. return hr;
  104. }
  105. //
  106. // Create the appropriate sink according to the Qos and add it to
  107. // the message service. Currently, all Qos types support overlapped i/o.
  108. //
  109. CWbemPtr<IWmiMessageReceiverSink> pSink;
  110. switch( m_dwFlags & WMIMSG_MASK_QOS )
  111. {
  112. case WMIMSG_FLAG_QOS_EXPRESS:
  113. hr = CMsgSimpleRcvSink::Create( m_pControl, m_pHndlr, this, &pSink );
  114. break;
  115. case WMIMSG_FLAG_QOS_GUARANTEED:
  116. hr = CMsgSafeRcvSink::Create( m_pControl, m_pHndlr, this, &pSink );
  117. break;
  118. default:
  119. return WBEM_E_NOT_SUPPORTED;
  120. };
  121. //
  122. // The SvcId will be used on release of the receiver to remove
  123. // the sink from the messsage service.
  124. //
  125. return m_pSvc->Add( pSink, &m_hQueue, 0, &m_pSvcId );
  126. }
  127. HRESULT CMsgMsmqReceiver::Open( LPCWSTR wszEndpoint,
  128. DWORD dwFlags,
  129. WMIMSG_RCVR_AUTH_INFOP pAuthInfo,
  130. IWmiMessageSendReceive* pRecv )
  131. {
  132. ENTER_API_CALL
  133. HRESULT hr;
  134. CInCritSec ics( &m_cs );
  135. hr = m_Api.Initialize();
  136. if ( FAILED(hr) )
  137. {
  138. return hr;
  139. }
  140. //
  141. // handle cleanup of open queues and open msg svc connections.
  142. //
  143. Close();
  144. //
  145. // need to save the endpoint and flags because we may need to reinitialize
  146. // at a later time.
  147. //
  148. m_wsEndpoint = wszEndpoint;
  149. m_dwFlags = dwFlags;
  150. m_pRecv = pRecv;
  151. //
  152. // rest of init takes place in EnsureReceiver(). This part of init will
  153. // also occur later when trying to recover from queue errors.
  154. //
  155. return EnsureReceiver();
  156. EXIT_API_CALL
  157. }
  158. HRESULT CMsgMsmqReceiver::HandleError( HRESULT hr )
  159. {
  160. CWbemPtr<IWmiMessageTraceSink> pTraceSink;
  161. if ( m_pRecv->QueryInterface( IID_IWmiMessageTraceSink,
  162. (void**)&pTraceSink ) == S_OK )
  163. {
  164. pTraceSink->Notify( MqResToWmiRes(hr),
  165. CLSID_WmiMessageMsmqReceiver,
  166. m_wsEndpoint,
  167. NULL );
  168. }
  169. return hr;
  170. }
  171. HRESULT CMsgMsmqReceiver::HandleReceiveError( HRESULT hr )
  172. {
  173. //
  174. // if this method returns Success, then it means that we should keep
  175. // keep receiving.
  176. //
  177. if ( hr == MQ_ERROR_INVALID_HANDLE || hr == MQ_ERROR_OPERATION_CANCELLED )
  178. {
  179. //
  180. // indicates shutdown. we want to stop receiving on the sink,
  181. // but since this is a benign error, don't notify the error sink.
  182. //
  183. return WBEM_E_SHUTTING_DOWN;
  184. }
  185. //
  186. // ask the handler if it needs to resize any of its buffers. If so,
  187. // then return success and we'll try again.
  188. //
  189. HRESULT hr2 = m_pHndlr->CheckBufferResize(hr);
  190. if ( hr2 != S_FALSE )
  191. {
  192. return hr2;
  193. }
  194. //
  195. // some errors we can attempt to recover from. Unfortunately, we
  196. // cannot tell here if this is one of those errors. So always try to
  197. // revive the receiver.
  198. //
  199. Close();
  200. hr2 = EnsureReceiver();
  201. //
  202. // always tell the trace sink about this error. If EnsureReceiver()
  203. // was successful, then the error will downgraded to a warning. TODO.
  204. //
  205. HandleError( hr );
  206. //
  207. // we always want to return the original error because we want the svc
  208. // to stop receiving on the original sink. If EnsureReceiver() is
  209. // successful, then a new sink will be created to take its place.
  210. //
  211. return hr;
  212. }
  213. /**************************************************************************
  214. CMsgSimpleRcvSink
  215. ***************************************************************************/
  216. STDMETHODIMP CMsgSimpleRcvSink::Receive( PVOID pOverlapped )
  217. {
  218. ENTER_API_CALL
  219. HRESULT hr;
  220. hr = m_pHndlr->ReceiveMessage( INFINITE,
  221. WMIMSG_ACTION_QRCV_RECEIVE,
  222. NULL,
  223. LPOVERLAPPED(pOverlapped),
  224. NULL );
  225. if ( FAILED(hr) )
  226. {
  227. return m_pRcvr->HandleReceiveError( hr );
  228. }
  229. return WBEM_S_NO_ERROR;
  230. EXIT_API_CALL
  231. }
  232. STDMETHODIMP CMsgSimpleRcvSink::Notify( PVOID pvOverlapped )
  233. {
  234. ENTER_API_CALL
  235. HRESULT hr;
  236. LPOVERLAPPED pOverlapped = LPOVERLAPPED(pvOverlapped);
  237. hr = ULONG(pOverlapped->Internal);
  238. if ( FAILED(hr) )
  239. {
  240. return m_pRcvr->HandleReceiveError( hr );
  241. }
  242. hr = m_pHndlr->HandleMessage( NULL );
  243. if ( FAILED(hr) )
  244. {
  245. //
  246. // we don't want to return this hr because we'll stop listening
  247. // on the sink. HandleError notifies the user, but we keep on
  248. // truckin. Its only when there is an error with receiving from
  249. // the queue handle that we stop receiving on the sink.
  250. //
  251. m_pRcvr->HandleError( hr );
  252. }
  253. return WBEM_S_NO_ERROR;
  254. EXIT_API_CALL
  255. }
  256. HRESULT CMsgSimpleRcvSink::Create( CLifeControl* pControl,
  257. CMsgMsmqHandler* pHndlr,
  258. CMsgMsmqReceiver* pRcvr,
  259. IWmiMessageReceiverSink** ppSink )
  260. {
  261. HRESULT hr;
  262. *ppSink = NULL;
  263. CWbemPtr<CMsgSimpleRcvSink> pSink;
  264. pSink = new CMsgSimpleRcvSink( pControl, pHndlr, pRcvr );
  265. if ( pSink == NULL )
  266. {
  267. return WBEM_E_OUT_OF_MEMORY;
  268. }
  269. return pSink->QueryInterface( IID_IWmiMessageReceiverSink, (void**)ppSink);
  270. }
  271. /**************************************************************************
  272. CMsgSafeRcvSink
  273. ***************************************************************************/
  274. STDMETHODIMP CMsgSafeRcvSink::Receive( PVOID pOverlapped )
  275. {
  276. ENTER_API_CALL
  277. HRESULT hr;
  278. hr = m_pHndlr->ReceiveMessage( INFINITE,
  279. WMIMSG_ACTION_QRCV_PEEK_CURRENT,
  280. NULL,
  281. LPOVERLAPPED(pOverlapped),
  282. NULL );
  283. if ( FAILED(hr) )
  284. {
  285. return m_pRcvr->HandleReceiveError(hr);
  286. }
  287. return WBEM_S_NO_ERROR;
  288. EXIT_API_CALL
  289. }
  290. STDMETHODIMP CMsgSafeRcvSink::Notify( PVOID pvOverlapped )
  291. {
  292. ENTER_API_CALL
  293. HRESULT hr;
  294. LPOVERLAPPED pOverlapped = LPOVERLAPPED(pvOverlapped);
  295. hr = ULONG(pOverlapped->Internal);
  296. if ( FAILED(hr) )
  297. {
  298. return m_pRcvr->HandleReceiveError( hr );
  299. }
  300. hr = m_pHndlr->HandleMessage( NULL );
  301. //
  302. // we don't want to return this hr because we'll stop listening
  303. // on the sink. HandleError notifies the user, but we keep on
  304. // truckin. Its only when there is an error with receiving from
  305. // the queue handle that we stop receiving on the sink.
  306. //
  307. if ( FAILED(hr) )
  308. {
  309. m_pRcvr->HandleError( hr );
  310. }
  311. hr = m_pHndlr->ReceiveMessage( INFINITE,
  312. WMIMSG_ACTION_QRCV_REMOVE,
  313. NULL,
  314. NULL,
  315. NULL );
  316. if ( FAILED(hr) )
  317. {
  318. return m_pRcvr->HandleReceiveError( hr );
  319. }
  320. return WBEM_S_NO_ERROR;
  321. EXIT_API_CALL
  322. }
  323. HRESULT CMsgSafeRcvSink::Create( CLifeControl* pControl,
  324. CMsgMsmqHandler* pHndlr,
  325. CMsgMsmqReceiver* pRcvr,
  326. IWmiMessageReceiverSink** ppSink )
  327. {
  328. HRESULT hr;
  329. *ppSink = NULL;
  330. CWbemPtr<CMsgSafeRcvSink> pSink;
  331. pSink = new CMsgSafeRcvSink( pControl, pHndlr, pRcvr );
  332. if ( pSink == NULL )
  333. {
  334. return WBEM_E_OUT_OF_MEMORY;
  335. }
  336. return pSink->QueryInterface(IID_IWmiMessageReceiverSink, (void**)ppSink);
  337. }