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.

645 lines
13 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. DataChannelMgr.cpp
  5. Abstract:
  6. This module contains an implementation of the ISAFRemoteDesktopDataChannel
  7. and ISAFRemoteDesktopChannelMgr interfaces. These interfaces are designed
  8. to abstract out-of-band data channel access for the Salem project.
  9. The classes implemented in this module achieve this objective by
  10. multiplexing multiple data channels into a single data channel that is
  11. implemented by the remote control-specific Salem layer.
  12. Author:
  13. Tad Brockway 02/00
  14. Revision History:
  15. --*/
  16. #ifdef TRC_FILE
  17. #undef TRC_FILE
  18. #endif
  19. #define TRC_FILE "_dcmpl"
  20. #include "DataChannelMgr.h"
  21. #include <RemoteDesktop.h>
  22. #include <RemoteDesktopDBG.h>
  23. ///////////////////////////////////////////////////////
  24. //
  25. // Local Defines
  26. //
  27. #define OUTBUFRESIZEDELTA 100
  28. ///////////////////////////////////////////////////////
  29. //
  30. // CRemoteDesktopChannelMgr Members
  31. //
  32. CRemoteDesktopChannelMgr::CRemoteDesktopChannelMgr()
  33. /*++
  34. Routine Description:
  35. Constructor
  36. Arguments:
  37. Return Value:
  38. None.
  39. --*/
  40. {
  41. DC_BEGIN_FN("CRemoteDesktopChannelMgr::CRemoteDesktopChannelMgr");
  42. #if DBG
  43. m_LockCount = 0;
  44. #endif
  45. //
  46. // Initialize the critical section.
  47. //
  48. InitializeCriticalSection(&m_cs);
  49. DC_END_FN();
  50. }
  51. CRemoteDesktopChannelMgr::~CRemoteDesktopChannelMgr()
  52. /*++
  53. Routine Description:
  54. Destructor
  55. Arguments:
  56. Return Value:
  57. None.
  58. --*/
  59. {
  60. DC_BEGIN_FN("CRemoteDesktopChannelMgr::~CRemoteDesktopChannelMgr");
  61. ThreadLock();
  62. CComBSTR name;
  63. CRemoteDesktopDataChannel *chnl;
  64. HRESULT hr;
  65. //
  66. // Remove each channel.
  67. //
  68. while (!m_ChannelMap.empty()) {
  69. chnl = (*m_ChannelMap.begin()).second->channelObject;
  70. RemoveChannel(chnl->m_ChannelName);
  71. }
  72. //
  73. // Clean up the critical section object.
  74. //
  75. ThreadUnlock();
  76. DeleteCriticalSection(&m_cs);
  77. DC_END_FN();
  78. }
  79. HRESULT
  80. CRemoteDesktopChannelMgr::OpenDataChannel_(
  81. BSTR name,
  82. ISAFRemoteDesktopDataChannel **channel
  83. )
  84. /*++
  85. Routine Description:
  86. Open a data channel. Observe that this function doesn't keep
  87. a reference of its own to the returned interface. The channel
  88. notifies us when it goes away so we can remove it from our list.
  89. Arguments:
  90. name - Channel name. Channel names are restricted to
  91. 16 bytes.
  92. channel - Returned channe linterface.
  93. Return Value:
  94. S_OK is returned on success. Otherwise, an error code
  95. is returned.
  96. --*/
  97. {
  98. DC_BEGIN_FN("CRemoteDesktopChannelMgr::OpenDataChannel_");
  99. PCHANNELMAPENTRY newChannel = NULL;
  100. ChannelMap::iterator iter;
  101. HRESULT hr = S_OK;
  102. CComBSTR channelName;
  103. ASSERT(IsValid());
  104. ThreadLock();
  105. //
  106. // Check the parms.
  107. //
  108. if ((name == NULL) || !wcslen(name)) {
  109. TRC_ERR((TB, TEXT("Invalid channel name")));
  110. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  111. goto CLEANUPANDEXIT;
  112. }
  113. if (channel == NULL) {
  114. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  115. goto CLEANUPANDEXIT;
  116. }
  117. channelName = name;
  118. //
  119. // AddRef an existing interface if the channel is already open.
  120. //
  121. iter = m_ChannelMap.find(channelName);
  122. if (iter != m_ChannelMap.end()) {
  123. TRC_NRM((TB, TEXT("Channel %s exists."), name));
  124. CRemoteDesktopDataChannel *chnl = (*iter).second->channelObject;
  125. hr = chnl->GetISAFRemoteDesktopDataChannel(channel);
  126. if (hr != S_OK) {
  127. TRC_ERR((TB, TEXT("GetISAFRemoteDesktopDataChannel failed: %08X"), hr));
  128. }
  129. goto CLEANUPANDEXIT;
  130. }
  131. //
  132. // Create the new channel with some help from the subclass.
  133. //
  134. newChannel = new CHANNELMAPENTRY;
  135. if (newChannel == NULL) {
  136. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  137. goto CLEANUPANDEXIT;
  138. }
  139. newChannel->channelObject = OpenPlatformSpecificDataChannel(
  140. name,
  141. channel
  142. );
  143. if (newChannel->channelObject == NULL) {
  144. TRC_ERR((TB, TEXT("Failed to allocate data channel.")));
  145. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  146. goto CLEANUPANDEXIT;
  147. }
  148. #if DBG
  149. newChannel->bytesSent = 0;
  150. newChannel->bytesRead = 0;
  151. #endif
  152. if (hr != S_OK) {
  153. TRC_ERR((TB, TEXT("QI failed for ISAFRemoteDesktopDataChannel")));
  154. goto CLEANUPANDEXIT;
  155. }
  156. //
  157. // Add the channel to the channel map.
  158. //
  159. try {
  160. m_ChannelMap.insert(ChannelMap::value_type(channelName, newChannel));
  161. }
  162. catch(CRemoteDesktopException x) {
  163. hr = HRESULT_FROM_WIN32(x.m_ErrorCode);
  164. }
  165. CLEANUPANDEXIT:
  166. if (hr != S_OK) {
  167. if (newChannel != NULL) {
  168. (*channel)->Release();
  169. delete newChannel;
  170. }
  171. }
  172. ThreadUnlock();
  173. DC_END_FN();
  174. return hr;
  175. }
  176. VOID
  177. CRemoteDesktopChannelMgr::RemoveChannel(
  178. BSTR channel
  179. )
  180. /*++
  181. Routine Description:
  182. Remove an existing data channel. This function is called from the
  183. channel object when its ref count goes to 0.
  184. Arguments:
  185. channel - Name of channel to remove.
  186. Return Value:
  187. None.
  188. --*/
  189. {
  190. DC_BEGIN_FN("CRemoteDesktopChannelMgr::RemoveChannel");
  191. ASSERT(IsValid());
  192. ChannelMap::iterator iter;
  193. PCHANNELMAPENTRY pChannel;
  194. ThreadLock();
  195. //
  196. // Find the channel.
  197. //
  198. iter = m_ChannelMap.find(channel);
  199. if (iter == m_ChannelMap.end()) {
  200. ASSERT(FALSE);
  201. TRC_ERR((TB, TEXT("Channel %ld does not exist."), channel));
  202. goto CLEANUPANDEXIT;
  203. }
  204. //
  205. // Release the input buffer queue and its contents.
  206. //
  207. pChannel = (*iter).second;
  208. while (!pChannel->inputBufferQueue.empty()) {
  209. QUEUEDCHANNELBUFFER channelBuf = pChannel->inputBufferQueue.front();
  210. SysFreeString(channelBuf.buf);
  211. pChannel->inputBufferQueue.pop_front();
  212. }
  213. //
  214. // Erase the channel.
  215. //
  216. m_ChannelMap.erase(iter);
  217. delete pChannel;
  218. CLEANUPANDEXIT:
  219. ThreadUnlock();
  220. DC_END_FN();
  221. }
  222. HRESULT
  223. CRemoteDesktopChannelMgr::SendChannelData(
  224. BSTR channel,
  225. BSTR outputBuf
  226. )
  227. /*++
  228. Routine Description:
  229. Send a buffer on the data channel.
  230. Arguments:
  231. channel - Relevant channel.
  232. outputBuf - Associated output data.
  233. Return Value:
  234. ERROR_SUCCESS is returned on success. Otherwise, an error code
  235. is returned.
  236. --*/
  237. {
  238. DC_BEGIN_FN("CRemoteDesktopChannelMgr::SendChannelData");
  239. ASSERT(IsValid());
  240. HRESULT result = S_OK;
  241. PREMOTEDESKTOP_CHANNELBUFHEADER hdr;
  242. DWORD bytesToSend;
  243. PBYTE data;
  244. BSTR fullOutputBuf;
  245. DWORD bufLen = SysStringByteLen(outputBuf);
  246. DWORD channelNameLen;
  247. PBYTE ptr;
  248. //
  249. // Make sure this is a valid channel.
  250. //
  251. ChannelMap::iterator iter;
  252. //
  253. // ThreadLock
  254. //
  255. ThreadLock();
  256. //
  257. // Make sure the channel exists.
  258. //
  259. iter = m_ChannelMap.find(channel);
  260. if (iter == m_ChannelMap.end()) {
  261. ASSERT(FALSE);
  262. goto CLEANUPANDEXIT;
  263. }
  264. #if DBG
  265. (*iter).second->bytesSent += SysStringByteLen(outputBuf);
  266. #endif
  267. //
  268. // Allocate the outgoing buffer.
  269. //
  270. channelNameLen = SysStringByteLen(channel);
  271. bytesToSend = sizeof(REMOTEDESKTOP_CHANNELBUFHEADER) + bufLen + channelNameLen;
  272. fullOutputBuf = (BSTR)SysAllocStringByteLen(
  273. NULL,
  274. bytesToSend
  275. );
  276. if (fullOutputBuf == NULL) {
  277. TRC_ERR((TB, TEXT("Can't allocate %ld bytes."),
  278. bytesToSend + OUTBUFRESIZEDELTA));
  279. result = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  280. goto CLEANUPANDEXIT;
  281. }
  282. //
  283. // Initialize the header.
  284. //
  285. hdr = (PREMOTEDESKTOP_CHANNELBUFHEADER)fullOutputBuf;
  286. memset(hdr, 0, sizeof(REMOTEDESKTOP_CHANNELBUFHEADER));
  287. #ifdef USE_MAGICNO
  288. hdr->magicNo = CHANNELBUF_MAGICNO;
  289. #endif
  290. hdr->channelNameLen = channelNameLen;
  291. hdr->dataLen = bufLen;
  292. //
  293. // Copy the channel name.
  294. //
  295. ptr = (PBYTE)(hdr + 1);
  296. memcpy(ptr, channel, hdr->channelNameLen);
  297. //
  298. // Copy the data.
  299. //
  300. ptr += hdr->channelNameLen;
  301. memcpy(ptr, outputBuf, bufLen);
  302. //
  303. // Send the data through the concrete subclass.
  304. //
  305. result = SendData(hdr);
  306. //
  307. // Release the send buffer that we allocated.
  308. //
  309. SysFreeString(fullOutputBuf);
  310. CLEANUPANDEXIT:
  311. ThreadUnlock();
  312. DC_END_FN();
  313. return result;
  314. }
  315. HRESULT
  316. CRemoteDesktopChannelMgr::ReadChannelData(
  317. IN BSTR channel,
  318. OUT BSTR *msg
  319. )
  320. /*++
  321. Routine Description:
  322. Read the next message from a data channel.
  323. Arguments:
  324. channel - Relevant data channel.
  325. msg - The next message. The caller should release the
  326. data buffer using SysFreeString.
  327. Return Value:
  328. S_OK on success. ERROR_NO_MORE_ITEMS is returned if there
  329. are no more messages. An error code otherwise.
  330. --*/
  331. {
  332. DC_BEGIN_FN("CRemoteDesktopChannelMgr::ReadChannelData");
  333. HRESULT result = S_OK;
  334. ChannelMap::iterator channelIterator;
  335. PCHANNELMAPENTRY pChannel;
  336. ASSERT(IsValid());
  337. ThreadLock();
  338. //
  339. // Initialize the output buf to NULL.
  340. //
  341. *msg = NULL;
  342. //
  343. // Find the channel.
  344. //
  345. channelIterator = m_ChannelMap.find(channel);
  346. if (channelIterator != m_ChannelMap.end()) {
  347. pChannel = (*channelIterator).second;
  348. }
  349. else {
  350. ASSERT(FALSE);
  351. result = E_FAIL;
  352. goto CLEANUPANDEXIT;
  353. }
  354. //
  355. // Make sure there is data in the queue.
  356. //
  357. if (pChannel->inputBufferQueue.empty()) {
  358. result = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  359. goto CLEANUPANDEXIT;
  360. }
  361. //
  362. // Return the buffer.
  363. //
  364. *msg = pChannel->inputBufferQueue.front().buf;
  365. ASSERT(*msg != NULL);
  366. //
  367. // Delete it.
  368. //
  369. pChannel->inputBufferQueue.pop_front();
  370. CLEANUPANDEXIT:
  371. ThreadUnlock();
  372. DC_END_FN();
  373. return result;
  374. }
  375. VOID
  376. CRemoteDesktopChannelMgr::DataReady(
  377. BSTR msg
  378. )
  379. /*++
  380. Routine Description:
  381. Invoked by the subclass when the next message is ready. This
  382. function copies the message buffer and returns.
  383. Arguments:
  384. msg - Next message.
  385. Return Value:
  386. None.
  387. --*/
  388. {
  389. DC_BEGIN_FN("CRemoteDesktopChannelMgr::DataReady");
  390. ChannelMap::iterator channel;
  391. QUEUEDCHANNELBUFFER channelBuf;
  392. PREMOTEDESKTOP_CHANNELBUFHEADER hdr = NULL;
  393. DWORD result = ERROR_SUCCESS;
  394. PVOID data;
  395. PBYTE ptr;
  396. BSTR tmp;
  397. CComBSTR channelName;
  398. ASSERT(IsValid());
  399. ASSERT(msg != NULL);
  400. hdr = (PREMOTEDESKTOP_CHANNELBUFHEADER)msg;
  401. #ifdef USE_MAGICNO
  402. ASSERT(hdr->magicNo == CHANNELBUF_MAGICNO);
  403. #endif
  404. //
  405. // Initialize the channel buf.
  406. //
  407. channelBuf.buf = NULL;
  408. //
  409. // Get the channel name.
  410. //
  411. tmp = SysAllocStringByteLen(NULL, hdr->channelNameLen);
  412. if (tmp == NULL) {
  413. TRC_ERR((TB, TEXT("Can't allocate channel name.")));
  414. goto CLEANUPANDEXIT;
  415. }
  416. ptr = (PBYTE)(hdr + 1);
  417. memcpy(tmp, ptr, hdr->channelNameLen);
  418. channelName.Attach(tmp);
  419. ThreadLock();
  420. //
  421. // Find the corresponding channel.
  422. //
  423. #ifdef USE_MAGICNO
  424. ASSERT(hdr->magicNo == CHANNELBUF_MAGICNO);
  425. #endif
  426. channel = m_ChannelMap.find(channelName);
  427. if (channel == m_ChannelMap.end()) {
  428. TRC_ALT((TB, L"Data received for non-existent channel %s",
  429. channelName.m_str));
  430. result = E_FAIL;
  431. ThreadUnlock();
  432. goto CLEANUPANDEXIT;
  433. }
  434. //
  435. // Copy the incoming data buffer.
  436. //
  437. ptr += hdr->channelNameLen;
  438. channelBuf.len = hdr->dataLen;
  439. channelBuf.buf = SysAllocStringByteLen(NULL, channelBuf.len);
  440. if (channelBuf.buf == NULL) {
  441. TRC_ERR((TB, TEXT("Can't allocate %ld bytes for buf."), channelBuf.len));
  442. result = E_FAIL;
  443. ThreadUnlock();
  444. goto CLEANUPANDEXIT;
  445. }
  446. memcpy(channelBuf.buf, ptr, hdr->dataLen);
  447. //
  448. // Add to the channel's input queue.
  449. //
  450. try {
  451. (*channel).second->inputBufferQueue.push_back(channelBuf);
  452. }
  453. catch(CRemoteDesktopException x) {
  454. result = x.m_ErrorCode;
  455. ASSERT(result != ERROR_SUCCESS);
  456. }
  457. //
  458. // Notify the interface that data is ready.
  459. //
  460. if (result == ERROR_SUCCESS) {
  461. (*channel).second->channelObject->DataReady();
  462. #if DBG
  463. (*channel).second->bytesRead += hdr->dataLen;
  464. #endif
  465. }
  466. ThreadUnlock();
  467. CLEANUPANDEXIT:
  468. if ((result != ERROR_SUCCESS) && (channelBuf.buf != NULL)) {
  469. SysFreeString(channelBuf.buf);
  470. }
  471. DC_END_FN();
  472. }