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.

521 lines
20 KiB

  1. /*****************************************************************************
  2. * (C) COPYRIGHT MICROSOFT CORPORATION, 2002
  3. *
  4. * AUTHOR: ByronC
  5. *
  6. * DATE: 3/22/2002
  7. *
  8. * @doc INTERNAL
  9. *
  10. * @module AsyncRPCEventTransport.cpp - Implementation for the client-side transport mechanism to receive events |
  11. *
  12. * This file contains the implementation for the <c AsyncRPCEventTransport>
  13. * class. It is used to shield the higher-level run-time event notification
  14. * classes from the particulars of using AsyncRPC as a transport mechanism
  15. * for event notifications.
  16. *
  17. *****************************************************************************/
  18. #include "cplusinc.h"
  19. #include "coredbg.h"
  20. /*****************************************************************************
  21. * @doc INTERNAL
  22. *
  23. * @mfunc | AsyncRPCEventTransport | AsyncRPCEventTransport |
  24. *
  25. * We initialize all member variables. In general, this sets the values to 0,
  26. * except:
  27. * <nl><md AsyncRPCEventTransport::m_ulSig> is set to be AsyncRPCEventTransport_UNINIT_SIG.
  28. *
  29. *****************************************************************************/
  30. AsyncRPCEventTransport::AsyncRPCEventTransport() :
  31. ClientEventTransport(),
  32. m_RpcBindingHandle(NULL),
  33. m_AsyncClientContext(NULL),
  34. m_SyncClientContext(NULL)
  35. {
  36. DBG_FN(AsyncRPCEventTransport);
  37. memset(&m_AsyncState, 0, sizeof(m_AsyncState));
  38. memset(&m_AsyncEventNotifyData, 0, sizeof(m_AsyncEventNotifyData));
  39. }
  40. /*****************************************************************************
  41. * @doc INTERNAL
  42. *
  43. * @mfunc | AsyncRPCEventTransport | ~AsyncRPCEventTransport |
  44. *
  45. * Do any cleanup that is not already done. Specifically, we:
  46. * <nl> - Call <mf AsyncRPCEventTransport::FreeAsyncEventNotifyData>.
  47. * <nl> - Call <mf AsyncRPCEventTransport::CloseNotificationChannel>.
  48. * <nl> - Call <mf AsyncRPCEventTransport::CloseConnectionToServer>.
  49. *
  50. * Also:
  51. * <nl><md AsyncRPCEventTransport::m_ulSig> is set to be AsyncRPCEventTransport_DEL_SIG.
  52. *
  53. *****************************************************************************/
  54. AsyncRPCEventTransport::~AsyncRPCEventTransport()
  55. {
  56. DBG_FN(~AsyncRPCEventTransport);
  57. FreeAsyncEventNotifyData();
  58. // Close notification channel and connection to server. In both cases
  59. // we're not interested in the return values.
  60. HRESULT hr = S_OK;
  61. hr = CloseNotificationChannel();
  62. hr = CloseConnectionToServer();
  63. m_AsyncClientContext = NULL;
  64. m_SyncClientContext = NULL;
  65. }
  66. /*****************************************************************************
  67. * @doc INTERNAL
  68. *
  69. * @mfunc HRESULT | AsyncRPCEventTransport | OpenConnectionToServer |
  70. *
  71. * This function does the necessary setup work needed to make our RPC calls.
  72. * Essentially, it simply binds to the RPC Server over LRPC. The RPC binding
  73. * handle is stored in the member variable
  74. * <mf AsyncRPCEventTransport::m_RpcBindingHandle>.
  75. *
  76. * If <mf AsyncRPCEventTransport::m_RpcBindingHandle> is not NULL, this method
  77. * will call <mf AsyncRPCEventTransport::CloseConnectionToServer> to free it,
  78. * and then attempt to establish a new connection.
  79. *
  80. * If successful, callers should clean-up by calling
  81. * <mf AsyncRPCEventTransport::CloseConnectionToServer>, although the destructor
  82. * will do it if the caller does not.
  83. *
  84. * @rvalue RPC_S_OK |
  85. * The function succeeded.
  86. * @rvalue RPC_XXXXXXX |
  87. * RPC Error code.
  88. *****************************************************************************/
  89. HRESULT AsyncRPCEventTransport::OpenConnectionToServer()
  90. {
  91. HRESULT hr = S_OK;
  92. DBG_TRC(("Opened connection to server"));
  93. RpcTryExcept
  94. {
  95. //
  96. // Check whether we have an existing connection. If we do, then close it.
  97. //
  98. if (m_RpcBindingHandle)
  99. {
  100. CloseConnectionToServer();
  101. m_RpcBindingHandle = NULL;
  102. }
  103. LPTSTR pszBinding = NULL;
  104. DWORD dwError = RPC_S_OK;
  105. //
  106. // Compose the binding string for local binding
  107. //
  108. dwError = RpcStringBindingCompose(NULL, // ObjUuid
  109. STI_LRPC_SEQ, // transport seq
  110. NULL, // NetworkAddr
  111. STI_LRPC_ENDPOINT, // Endpoint
  112. NULL, // Options
  113. &pszBinding); // StringBinding
  114. if ( dwError == RPC_S_OK )
  115. {
  116. //
  117. // establish the binding handle using string binding.
  118. //
  119. dwError = RpcBindingFromStringBinding(pszBinding,&m_RpcBindingHandle);
  120. if (dwError == RPC_S_OK)
  121. {
  122. //
  123. // Check that the server we're connecting to has the appropriate credentials.
  124. // In our case, we don't know exactly which principal name the WIA Service
  125. // is running under, so we need to look it up.
  126. // Note that we assume the Services section of the registry is secure, and
  127. // only Admins can change it.
  128. // Also note that we default to "NT Authority\LocalService" if we cannot read the key.
  129. //
  130. CSimpleReg csrStiSvcKey(HKEY_LOCAL_MACHINE, STISVC_REG_PATH, FALSE, KEY_READ);
  131. CSimpleStringWide cswStiSvcPrincipalName = csrStiSvcKey.Query(L"ObjectName", L"NT Authority\\LocalService");
  132. RPC_SECURITY_QOS RpcSecQos = {0};
  133. RpcSecQos.Version = RPC_C_SECURITY_QOS_VERSION_1;
  134. RpcSecQos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  135. RpcSecQos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
  136. RpcSecQos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
  137. dwError = RpcBindingSetAuthInfoExW(m_RpcBindingHandle,
  138. (WCHAR*)cswStiSvcPrincipalName.String(),
  139. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  140. RPC_C_AUTHN_WINNT,
  141. NULL,
  142. RPC_C_AUTHZ_NONE,
  143. &RpcSecQos);
  144. if (dwError == RPC_S_OK)
  145. {
  146. DBG_TRC(("AsyncRPC Connection established to server"));
  147. dwError = OpenClientConnection(m_RpcBindingHandle, &m_SyncClientContext, &m_AsyncClientContext);
  148. if (dwError == RPC_S_OK)
  149. {
  150. DBG_TRC(("Got my context %p from server\n", m_AsyncClientContext));
  151. }
  152. else
  153. {
  154. DBG_ERR(("Runtime event: Received error 0x%08X trying to open connection to server", dwError));
  155. }
  156. }
  157. else
  158. {
  159. DBG_ERR(("Error 0x%08X trying to set RPC Authentication Info", dwError));
  160. }
  161. }
  162. //
  163. // Free the binding string since we no longer need it
  164. //
  165. if (pszBinding != NULL)
  166. {
  167. DWORD dwErr = RpcStringFree(&pszBinding);
  168. pszBinding = NULL;
  169. }
  170. }
  171. else
  172. {
  173. DBG_ERR(("Runtime event Error: Could not create binding string to establish connection to server, error 0x%08X", dwError));
  174. }
  175. }
  176. RpcExcept (1)
  177. {
  178. // TBD: Should we catch all exceptions? Probably not...
  179. DWORD status = RpcExceptionCode();
  180. hr = HRESULT_FROM_WIN32(status);
  181. }
  182. RpcEndExcept
  183. return hr;
  184. }
  185. /*****************************************************************************
  186. * @doc INTERNAL
  187. *
  188. * @mfunc HRESULT | AsyncRPCEventTransport | CloseConnectionToServer |
  189. *
  190. * This method is imlemented by sub-classes to close any resources used to
  191. * connect to the WIA service in <mf AsyncRPCEventTransport::OpenConnectionToServer>.
  192. *
  193. * @rvalue S_OK |
  194. * The method succeeded.
  195. * @rvalue E_XXXXXXXX |
  196. * We received an error closing the connection to the server.
  197. *****************************************************************************/
  198. HRESULT AsyncRPCEventTransport::CloseConnectionToServer()
  199. {
  200. HRESULT hr = S_OK;
  201. DWORD dwError = 0;
  202. if (m_RpcBindingHandle)
  203. {
  204. RpcTryExcept
  205. {
  206. CloseClientConnection(m_RpcBindingHandle, m_SyncClientContext);
  207. dwError = RpcBindingFree(&m_RpcBindingHandle);
  208. if (dwError == RPC_S_OK)
  209. {
  210. DBG_TRC(("Closed Async connection to server"));
  211. }
  212. else
  213. {
  214. hr = HRESULT_FROM_WIN32(dwError);
  215. DBG_ERR(("Runtime event Error: Got return code 0x%08X freeing RPC binding handle", dwError));
  216. }
  217. }
  218. RpcExcept (1) {
  219. // TBD: Should we catch all exceptions? Probably not...
  220. DWORD status = RpcExceptionCode();
  221. hr = HRESULT_FROM_WIN32(status);
  222. }
  223. RpcEndExcept
  224. m_RpcBindingHandle = NULL;
  225. }
  226. DBG_TRC(("Closed connection to server"));
  227. return hr;
  228. }
  229. /*****************************************************************************
  230. * @doc INTERNAL
  231. *
  232. * @mfunc HRESULT | AsyncRPCEventTransport | OpenNotificationChannel |
  233. *
  234. * Sub-classes use this method to set up the mechanism by which the client
  235. * will receive notifications.
  236. *
  237. * @rvalue S_OK |
  238. * The method succeeded.
  239. *****************************************************************************/
  240. HRESULT AsyncRPCEventTransport::OpenNotificationChannel()
  241. {
  242. HRESULT hr = S_OK;
  243. DBG_TRC(("Opened Async notification channel..."));
  244. RpcTryExcept
  245. {
  246. hr = RpcAsyncInitializeHandle(&m_AsyncState, sizeof(m_AsyncState));
  247. if (hr == RPC_S_OK)
  248. {
  249. m_AsyncState.UserInfo = NULL;
  250. m_AsyncState.u.hEvent = m_hPendingEvent;
  251. m_AsyncState.NotificationType = RpcNotificationTypeEvent;
  252. //
  253. // Make the Async RPC call. When this call completes, it typically
  254. // signifies that we have an event notification. However, it will
  255. // also complete on error conditions such as whent the server dies.
  256. // Therefore, it is important to check how it completed.
  257. //
  258. WiaGetRuntimetEventDataAsync(&m_AsyncState,
  259. m_RpcBindingHandle,
  260. m_AsyncClientContext,
  261. &m_AsyncEventNotifyData);
  262. }
  263. else
  264. {
  265. DBG_ERR(("Runtime event Error: Could not initialize the RPC_ASYNC_STATE structure, err = 0x%08X", hr));
  266. }
  267. }
  268. RpcExcept (1) {
  269. // TBD: Should we catch all exceptions? Probably not...
  270. DWORD status = RpcExceptionCode();
  271. hr = HRESULT_FROM_WIN32(status);
  272. }
  273. RpcEndExcept
  274. return hr;
  275. }
  276. /*****************************************************************************
  277. * @doc INTERNAL
  278. *
  279. * @mfunc HRESULT | AsyncRPCEventTransport | CloseNotificationChannel |
  280. *
  281. * If we have a pending AsyncRPC call, cancel it immediately (i.e. don't wait
  282. * for server to respond).
  283. *
  284. * @rvalue RPC_S_OK |
  285. * The method succeeded.
  286. * @rvalue E_XXXXXXX |
  287. * Failed to cancel the call.
  288. *****************************************************************************/
  289. HRESULT AsyncRPCEventTransport::CloseNotificationChannel()
  290. {
  291. HRESULT hr = S_OK;
  292. DBG_TRC(("Closed Async Notification channel"));
  293. RpcTryExcept
  294. {
  295. if (RpcAsyncGetCallStatus(&m_AsyncState) == RPC_S_ASYNC_CALL_PENDING)
  296. {
  297. hr = RpcAsyncCancelCall(&m_AsyncState,
  298. TRUE); // Return immediately - don't wait for server to respond.
  299. }
  300. }
  301. RpcExcept (1) {
  302. // TBD: Should we catch all exceptions? Probably not...
  303. DWORD status = RpcExceptionCode();
  304. hr = HRESULT_FROM_WIN32(status);
  305. }
  306. RpcEndExcept
  307. return hr;
  308. }
  309. /*****************************************************************************
  310. * @doc INTERNAL
  311. *
  312. * @mfunc HRESULT | AsyncRPCEventTransport | SendRegisterUnregisterInfo |
  313. *
  314. * Sends the registration information to the WIA Service via a synchronous RPC
  315. * call.
  316. *
  317. * @parm EventRegistrationInfo* | pEventRegistrationInfo |
  318. * The address of a caller's event registration information.
  319. *
  320. * @rvalue S_OK |
  321. * The method succeeded.
  322. * @rvalue E_XXXXXXXX |
  323. * Could not successfully send the registration info.
  324. *****************************************************************************/
  325. HRESULT AsyncRPCEventTransport::SendRegisterUnregisterInfo(
  326. EventRegistrationInfo *pEventRegistrationInfo)
  327. {
  328. HRESULT hr = S_OK;
  329. RpcTryExcept
  330. {
  331. if (pEventRegistrationInfo)
  332. {
  333. WIA_ASYNC_EVENT_REG_DATA wiaAsyncEventRegData = {0};
  334. wiaAsyncEventRegData.dwFlags = pEventRegistrationInfo->getFlags();
  335. wiaAsyncEventRegData.guidEvent = pEventRegistrationInfo->getEventGuid();
  336. wiaAsyncEventRegData.bstrDeviceID = pEventRegistrationInfo->getDeviceID();
  337. wiaAsyncEventRegData.ulCallback = pEventRegistrationInfo->getCallback();
  338. hr = RegisterUnregisterForEventNotification(m_RpcBindingHandle,
  339. m_SyncClientContext,
  340. &wiaAsyncEventRegData);
  341. DBG_TRC(("Sent RPC Register/Unregister information."));
  342. }
  343. else
  344. {
  345. DBG_ERR(("Runtime event Error: NULL event reg data passed to Transport."));
  346. hr = E_POINTER;
  347. }
  348. }
  349. RpcExcept (1) {
  350. // TBD: Should we catch all exceptions? Probably not...
  351. DWORD status = RpcExceptionCode();
  352. hr = HRESULT_FROM_WIN32(status);
  353. }
  354. RpcEndExcept
  355. return hr;
  356. }
  357. /*****************************************************************************
  358. * @doc INTERNAL
  359. *
  360. * @mfunc HRESULT | AsyncRPCEventTransport | FillEventData |
  361. *
  362. * Description goes here
  363. *
  364. * @parm WiaEventInfo* | pWiaEventInfo |
  365. * Address of the caller allocated pWiaEventInfo. The members of this class
  366. * are filled out with the relevant event info. It is the caller's
  367. * responsibility to free and memory allocated for the structure members.
  368. *
  369. * @rvalue S_OK |
  370. * The method succeeded.
  371. *****************************************************************************/
  372. HRESULT AsyncRPCEventTransport::FillEventData(
  373. WiaEventInfo *pWiaEventInfo)
  374. {
  375. HRESULT hr = RPC_S_ASYNC_CALL_PENDING;
  376. if (pWiaEventInfo)
  377. {
  378. RpcTryExcept
  379. {
  380. DWORD dwRet = 0;
  381. //
  382. // First check that the call is not still pending. If it isn't, we
  383. // complete the call and check whether is was successful or not.
  384. // Only if it was successful do we fill out the event data.
  385. //
  386. if (RpcAsyncGetCallStatus(&m_AsyncState) != RPC_S_ASYNC_CALL_PENDING)
  387. {
  388. hr = RpcAsyncCompleteCall(&m_AsyncState, &dwRet);
  389. if (hr == RPC_S_OK)
  390. {
  391. //
  392. // We successfully received an event from the server.
  393. // Fill out the event data for the caller.
  394. //
  395. pWiaEventInfo->setEventGuid(m_AsyncEventNotifyData.EventGuid);
  396. pWiaEventInfo->setEventDescription(m_AsyncEventNotifyData.bstrEventDescription);
  397. pWiaEventInfo->setDeviceID(m_AsyncEventNotifyData.bstrDeviceID);
  398. pWiaEventInfo->setDeviceDescription(m_AsyncEventNotifyData.bstrDeviceDescription);
  399. pWiaEventInfo->setDeviceType(m_AsyncEventNotifyData.dwDeviceType);
  400. pWiaEventInfo->setFullItemName(m_AsyncEventNotifyData.bstrFullItemName);
  401. pWiaEventInfo->setEventType(m_AsyncEventNotifyData.ulEventType);
  402. //
  403. // Free any data allocated for the m_AsyncEventNotifyData structure.
  404. //
  405. FreeAsyncEventNotifyData();
  406. }
  407. else
  408. {
  409. //
  410. // Clear the m_AsyncEventNotifyData since the info contained in their
  411. // is undefined when the server throws an error.
  412. //
  413. memset(&m_AsyncEventNotifyData, 0, sizeof(m_AsyncEventNotifyData));
  414. DBG_ERR(("Runtime event Error: The server returned an error 0x%08X completing the call", hr));
  415. }
  416. //
  417. // Our AsyncRPC call is a one-shot deal: once the call is completed, we have to make
  418. // another call to receive the next notification. So we simply call
  419. // OpenNotificationChannel again.
  420. //
  421. if (hr == RPC_S_OK)
  422. {
  423. dwRet = OpenNotificationChannel();
  424. }
  425. }
  426. else
  427. {
  428. DBG_ERR(("Runtime event Error: The async call is still pending."));
  429. hr = RPC_S_ASYNC_CALL_PENDING;
  430. }
  431. }
  432. RpcExcept (1) {
  433. // TBD: Should we catch all exceptions? Probably not...
  434. DWORD status = RpcExceptionCode();
  435. hr = HRESULT_FROM_WIN32(status);
  436. }
  437. RpcEndExcept
  438. }
  439. else
  440. {
  441. DBG_ERR(("Runtime event Error: FillEventData cannot fill in a NULL argument."));
  442. hr = E_INVALIDARG;
  443. }
  444. return hr;
  445. }
  446. /*****************************************************************************
  447. * @doc INTERNAL
  448. *
  449. * @mfunc VOID | AsyncRPCEventTransport | FreeAsyncEventNotifyData |
  450. *
  451. * Releases any memory that was allocated for the members contained in
  452. * <md AsyncRPCEventTransport::m_AsyncEventNotifyData> and zeros out
  453. * the members.
  454. *
  455. * This method is not thread safe: the caller of this class is expected to
  456. * synchronize access to it.
  457. *
  458. *****************************************************************************/
  459. VOID AsyncRPCEventTransport::FreeAsyncEventNotifyData()
  460. {
  461. if (m_AsyncEventNotifyData.bstrEventDescription)
  462. {
  463. SysFreeString(m_AsyncEventNotifyData.bstrEventDescription);
  464. m_AsyncEventNotifyData.bstrEventDescription = NULL;
  465. }
  466. if (m_AsyncEventNotifyData.bstrDeviceID)
  467. {
  468. SysFreeString(m_AsyncEventNotifyData.bstrDeviceID);
  469. m_AsyncEventNotifyData.bstrDeviceID = NULL;
  470. }
  471. if (m_AsyncEventNotifyData.bstrDeviceDescription)
  472. {
  473. SysFreeString(m_AsyncEventNotifyData.bstrDeviceDescription);
  474. m_AsyncEventNotifyData.bstrDeviceDescription = NULL;
  475. }
  476. if (m_AsyncEventNotifyData.bstrFullItemName)
  477. {
  478. SysFreeString(m_AsyncEventNotifyData.bstrFullItemName);
  479. m_AsyncEventNotifyData.bstrFullItemName = NULL;
  480. }
  481. memset(&m_AsyncEventNotifyData, 0, sizeof(m_AsyncEventNotifyData));
  482. }