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.

499 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name :
  4. exchnge.cpp
  5. Abstract:
  6. Implements methods associated with the exchange context structure. The
  7. exchange context provides context for an I/O transaction with the client
  8. Revision History:
  9. --*/
  10. #include "precomp.hxx"
  11. #define TRC_FILE "exchnge"
  12. #include "trc.h"
  13. DrExchangeManager::DrExchangeManager()
  14. {
  15. BEGIN_FN("DrExchangeManager::DrExchangeManager");
  16. SetClassName("DrExchangeManager");
  17. _RxMidAtlas = NULL;
  18. _demsState = demsStopped;
  19. _Session = NULL;
  20. }
  21. BOOL DrExchangeManager::Initialize(DrSession *Session)
  22. {
  23. BEGIN_FN("DrExchangeManager::Initialize");
  24. ASSERT(_Session == NULL);
  25. ASSERT(Session != NULL);
  26. _Session = Session;
  27. return !NT_ERROR(_Session->RegisterPacketReceiver(this));
  28. }
  29. VOID DrExchangeManager::Uninitialize()
  30. /*++
  31. Routine Description:
  32. Called if the exchange manager wasn't started because something
  33. went wrong during startup
  34. --*/
  35. {
  36. BEGIN_FN("DrExchangeManager::Uninitialize");
  37. ASSERT(_Session != NULL);
  38. ASSERT(_demsState == demsStopped);
  39. _Session->RemovePacketReceiver(this);
  40. _Session = NULL;
  41. }
  42. BOOL DrExchangeManager::Start()
  43. /*++
  44. Routine Description:
  45. Start and stop really exist because there's no way to clear everything
  46. out of a RxMidAtlas without destroying it. So start creates it and stop
  47. destroys it.
  48. Start simply allocates the Atlas and returns whether that worked
  49. Arguments:
  50. None.
  51. Return Value:
  52. Boolean indication of whether we can do IO
  53. --*/
  54. {
  55. DrExchangeManagerState demsState;
  56. BEGIN_FN("DrExchangeManager::Start");
  57. demsState = (DrExchangeManagerState)InterlockedExchange((long *)&_demsState, demsStarted);
  58. if (demsState == demsStopped) {
  59. TRC_DBG((TB, "Creating Atlas"));
  60. ASSERT(_RxMidAtlas == NULL);
  61. _RxMidAtlas = RxCreateMidAtlas(DR_MAX_OPERATIONS,
  62. DR_TYPICAL_OPERATIONS);
  63. } else {
  64. // The exchange has already started, so ignore this
  65. }
  66. TRC_DBG((TB, "Atlas 0x%p", _RxMidAtlas));
  67. return _RxMidAtlas != NULL;
  68. }
  69. VOID DrExchangeManager::Stop()
  70. {
  71. PRX_MID_ATLAS RxMidAtlas;
  72. DrExchangeManagerState demsState;
  73. BEGIN_FN("DrExchangeManager::Stop");
  74. demsState = (DrExchangeManagerState)InterlockedExchange((long *)&_demsState, demsStopped);
  75. if (demsState == demsStarted) {
  76. ASSERT(_RxMidAtlas != NULL);
  77. DrAcquireMutex();
  78. RxMidAtlas = _RxMidAtlas;
  79. _RxMidAtlas = NULL;
  80. DrReleaseMutex();
  81. TRC_NRM((TB, "Destroying Atlas 0x%p", RxMidAtlas));
  82. RxDestroyMidAtlas(RxMidAtlas, (PCONTEXT_DESTRUCTOR)DestroyAtlasCallback);
  83. } else {
  84. //
  85. // We allow this multiple times because this is how you cancel
  86. // outstanding client I/O
  87. //
  88. TRC_DBG((TB, "Atlas already destroyed"));
  89. }
  90. }
  91. VOID DrExchangeManager::DestroyAtlasCallback(DrExchange *pExchange)
  92. /*++
  93. Routine Description:
  94. Part of clearing out all the outstanding IO. Since we won't be able
  95. to complete this normally, we have to delete the Exchange
  96. Arguments:
  97. RxContext - Context to cancel and delete and whatnot
  98. Return Value:
  99. None.
  100. --*/
  101. {
  102. DrExchangeManager *ExchangeManager;
  103. PRX_CONTEXT RxContext = NULL;
  104. SmartPtr<DrExchange> Exchange;
  105. BEGIN_FN_STATIC("DrExchangeManager::DestroyAtlasCallback");
  106. //
  107. // Convert to a smart pointer and get rid of the explicit refcount
  108. //
  109. Exchange = pExchange;
  110. pExchange->Release();
  111. //
  112. // Notification that the conversation is over
  113. //
  114. Exchange->_ExchangeUser->OnIoDisconnected(Exchange);
  115. }
  116. BOOL DrExchangeManager::CreateExchange(IExchangeUser *ExchangeUser,
  117. PVOID Context, SmartPtr<DrExchange> &Exchange)
  118. /*++
  119. Routine Description:
  120. Creates an Exchange context data structure and initializes it
  121. with the basic data
  122. Arguments:
  123. ExchangeUser - An interface for callbacks associated with the conversation
  124. Context - ExchangeUser contextual data
  125. Exchange - Reference to where to put the results
  126. Return Value:
  127. Boolean success or failure
  128. --*/
  129. {
  130. BOOL rc = TRUE;
  131. NTSTATUS Status;
  132. USHORT Mid;
  133. BEGIN_FN("DrExchangeManager::CreateExchange");
  134. ASSERT(ExchangeUser != NULL);
  135. Exchange = new DrExchange(this, ExchangeUser, Context);
  136. if (Exchange != NULL) {
  137. DrAcquireMutex();
  138. if (_RxMidAtlas != NULL) {
  139. Status = RxAssociateContextWithMid(_RxMidAtlas, Exchange, &Mid);
  140. } else {
  141. Status = STATUS_DEVICE_NOT_CONNECTED;
  142. }
  143. if (NT_SUCCESS(Status)) {
  144. Exchange->_Mid = Mid;
  145. //
  146. // Explicit reference count for the atlas
  147. //
  148. Exchange->AddRef();
  149. } else {
  150. rc = FALSE;
  151. }
  152. DrReleaseMutex();
  153. if (!rc) {
  154. Exchange = NULL;
  155. }
  156. } else {
  157. rc = FALSE;
  158. }
  159. return rc;
  160. }
  161. DrExchange::DrExchange(DrExchangeManager *ExchangeManager,
  162. IExchangeUser *ExchangeUser, PVOID Context)
  163. /*++
  164. Routine Description:
  165. Constructor initializes member variables
  166. Arguments:
  167. ExchangeManager - Relevant manager
  168. Context - Context to track this op
  169. Return Value:
  170. None
  171. --*/
  172. {
  173. BEGIN_FN("DrExchange::DrExchange");
  174. ASSERT(ExchangeManager != NULL);
  175. ASSERT(ExchangeUser != NULL);
  176. _Context = Context;
  177. _ExchangeManager = ExchangeManager;
  178. _ExchangeUser = ExchangeUser;
  179. _Mid = INVALID_MID;
  180. }
  181. DrExchange::~DrExchange()
  182. {
  183. BEGIN_FN("DrExchange::~DrExchange");
  184. }
  185. BOOL DrExchangeManager::Find(USHORT Mid, SmartPtr<DrExchange> &ExchangeFound)
  186. /*++
  187. Routine Description:
  188. Marks an Exchange context as busy so it won't be cancelled
  189. while we're copying in to its buffer
  190. Arguments:
  191. Mid - Id to find
  192. ExchangeFound - storage for the pointer to the context
  193. Return Value:
  194. BOOL indicating whether it was found
  195. --*/
  196. {
  197. NTSTATUS Status;
  198. DrExchange *Exchange = NULL;
  199. BEGIN_FN("DrExchangeManager::Find");
  200. DrAcquireMutex();
  201. if (_RxMidAtlas != NULL) {
  202. Exchange = (DrExchange *)RxMapMidToContext(_RxMidAtlas, Mid);
  203. TRC_DBG((TB, "Found context: 0x%p", Exchange));
  204. }
  205. //
  206. // This is where the Exchange is reference counted, must be
  207. // inside the lock
  208. //
  209. ExchangeFound = Exchange;
  210. DrReleaseMutex();
  211. return ExchangeFound != NULL;
  212. }
  213. BOOL DrExchangeManager::ReadMore(ULONG cbSaveData, ULONG cbWantData)
  214. {
  215. BEGIN_FN("DrExchangeManager::ReadMore");
  216. return _Session->ReadMore(cbSaveData, cbWantData);
  217. }
  218. VOID DrExchangeManager::Discard(SmartPtr<DrExchange> &Exchange)
  219. /*++
  220. Routine Description:
  221. Stops tracking this as a conversation by its ID. the exchange will be
  222. deleted when its reference count goes to zero
  223. Arguments:
  224. Exchange - Marker for the operation
  225. Return Value:
  226. None.
  227. --*/
  228. {
  229. USHORT Mid;
  230. NTSTATUS Status;
  231. DrExchange *ExchangeFound = NULL;
  232. BEGIN_FN("DrExchangeManager::Discard");
  233. ASSERT(Exchange != NULL);
  234. DrAcquireMutex();
  235. Mid = Exchange->_Mid;
  236. if (_RxMidAtlas != NULL) {
  237. //
  238. // We already have the DrExchange, but we need to remove
  239. // it from the atlas
  240. //
  241. Status = RxMapAndDissociateMidFromContext(_RxMidAtlas,
  242. Mid, (PVOID *)&ExchangeFound);
  243. TRC_ASSERT(ExchangeFound == Exchange, (TB, "Mismatched "
  244. "DrExchange"));
  245. //
  246. // Explicit reference count for the atlas
  247. //
  248. if (ExchangeFound != NULL)
  249. ExchangeFound->Release();
  250. } else {
  251. TRC_ALT((TB, "Tried to complete mid when atlas was "
  252. "NULL"));
  253. Status = STATUS_DEVICE_NOT_CONNECTED;
  254. }
  255. DrReleaseMutex();
  256. }
  257. BOOL DrExchangeManager::RecognizePacket(PRDPDR_HEADER RdpdrHeader)
  258. {
  259. BEGIN_FN("DrExchangeManager::RecognizePacket");
  260. //
  261. // If you add a packet here, update the ASSERTS in HandlePacket
  262. //
  263. switch (RdpdrHeader->Component) {
  264. case RDPDR_CTYP_CORE:
  265. switch (RdpdrHeader->PacketId) {
  266. case DR_CORE_DEVICE_IOCOMPLETION:
  267. return TRUE;
  268. }
  269. }
  270. return FALSE;
  271. }
  272. NTSTATUS DrExchangeManager::HandlePacket(PRDPDR_HEADER RdpdrHeader,
  273. ULONG Length, BOOL *DoDefaultRead)
  274. {
  275. NTSTATUS Status;
  276. BEGIN_FN("DrExchangeManager::HandlePacket");
  277. //
  278. // RdpdrHeader read, dispatch based on the header
  279. //
  280. ASSERT(RdpdrHeader != NULL);
  281. ASSERT(Length >= sizeof(RDPDR_HEADER));
  282. ASSERT(RdpdrHeader->Component == RDPDR_CTYP_CORE);
  283. switch (RdpdrHeader->Component) {
  284. case RDPDR_CTYP_CORE:
  285. ASSERT(RdpdrHeader->PacketId == DR_CORE_DEVICE_IOCOMPLETION);
  286. switch (RdpdrHeader->PacketId) {
  287. case DR_CORE_DEVICE_IOCOMPLETION:
  288. Status = OnDeviceIoCompletion(RdpdrHeader, Length,
  289. DoDefaultRead);
  290. break;
  291. }
  292. }
  293. return Status;
  294. }
  295. NTSTATUS DrExchangeManager::OnDeviceIoCompletion(PRDPDR_HEADER RdpdrHeader,
  296. ULONG cbPacket, BOOL *DoDefaultRead)
  297. /*++
  298. Routine Description:
  299. Called in response to recognizing a DeviceIoCompletion packet has been
  300. received. Finds the associated RxContext, fills out relevant information,
  301. and completes the request.
  302. Arguments:
  303. RdpdrHeader - The header of the packet, a pointer to the packet
  304. cbPacket - The number of bytes of data in the packet
  305. Return Value:
  306. NTSTATUS - Success/failure indication of the operation
  307. --*/
  308. {
  309. NTSTATUS Status;
  310. PRX_CONTEXT RxContext;
  311. PRDPDR_IOCOMPLETION_PACKET CompletionPacket =
  312. (PRDPDR_IOCOMPLETION_PACKET)RdpdrHeader;
  313. SmartPtr<DrExchange> Exchange;
  314. USHORT Mid;
  315. ULONG cbMinimum;
  316. BEGIN_FN("DrExchangeManager::OnDeviceIoCompletion");
  317. cbMinimum = FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  318. IoCompletion.Parameters);
  319. if (cbMinimum > cbPacket) {
  320. *DoDefaultRead = FALSE;
  321. return _Session->ReadMore(cbPacket, cbMinimum);
  322. }
  323. Mid = (USHORT)CompletionPacket->IoCompletion.CompletionId;
  324. TRC_DBG((TB, "IoCompletion mid: %x", Mid));
  325. if (Find(Mid, Exchange)) {
  326. Status = Exchange->_ExchangeUser->OnDeviceIoCompletion(CompletionPacket,
  327. cbPacket, DoDefaultRead, Exchange);
  328. } else {
  329. //
  330. // Client gave us a bogus mid
  331. //
  332. Status = STATUS_DEVICE_PROTOCOL_ERROR;
  333. *DoDefaultRead = FALSE;
  334. }
  335. return Status;
  336. }
  337. NTSTATUS DrExchangeManager::StartExchange(SmartPtr<DrExchange> &Exchange,
  338. class IExchangeUser *ExchangeUser, PVOID Buffer, ULONG Length,
  339. BOOL LowPrioSend)
  340. /*++
  341. Routine Description:
  342. Sends the information to the client, and recognizes the response.
  343. Arguments:
  344. Exchange - The conversanion token
  345. Buffer - Data to send
  346. Length - size of the data
  347. LowPrioSend - Should the data be sent to the client at low priority.
  348. Return Value:
  349. Status of sending, a failure means no callback will be made
  350. --*/
  351. {
  352. NTSTATUS Status;
  353. BEGIN_FN("DrExchangeManager::StartExchange");
  354. Exchange->_ExchangeUser = ExchangeUser;
  355. //
  356. // This is a synchronous write
  357. //
  358. Status = _Session->SendToClient(Buffer, Length, this, FALSE,
  359. LowPrioSend, (PVOID)Exchange);
  360. return Status;
  361. }
  362. NTSTATUS DrExchangeManager::SendCompleted(PVOID Context,
  363. PIO_STATUS_BLOCK IoStatusBlock)
  364. {
  365. DrExchange *pExchange;
  366. SmartPtr<DrExchange> Exchange;
  367. BEGIN_FN("DrExchangeManager::SendCompleted");
  368. pExchange = (DrExchange *)Context;
  369. ASSERT(pExchange != NULL);
  370. ASSERT(pExchange->IsValid());
  371. Exchange = pExchange;
  372. return Exchange->_ExchangeUser->OnStartExchangeCompletion(Exchange,
  373. IoStatusBlock);
  374. }