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.

1169 lines
28 KiB

  1. /*++
  2. * File name:
  3. * queues.c
  4. * Contents:
  5. * Supports the linked lists for the clients
  6. * and events
  7. * Two linked lists:
  8. * g_pClientQHead - list of all clients running within smclient
  9. * g_pWaitQHead - all events we are waiting for from smclient
  10. *
  11. * Copyright (C) 1998-1999 Microsoft Corp.
  12. --*/
  13. #include <windows.h>
  14. #include <stdio.h>
  15. #include <malloc.h>
  16. #include <process.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <ctype.h>
  20. #include "tclient.h"
  21. #include "protocol.h"
  22. #include "gdata.h"
  23. #include "bmpcache.h"
  24. /*
  25. *
  26. * ClientQ functions
  27. *
  28. */
  29. /*++
  30. * Function:
  31. * _AddToClientQ
  32. * Description:
  33. * Adds a client on the top of the list
  34. * Arguments:
  35. * pClient - the client context
  36. * Called by:
  37. * SCConnect
  38. --*/
  39. VOID _AddToClientQ(PCONNECTINFO pClient)
  40. {
  41. EnterCriticalSection(g_lpcsGuardWaitQueue);
  42. pClient->pNext = g_pClientQHead;
  43. g_pClientQHead = pClient;
  44. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  45. }
  46. /*++
  47. * Function:
  48. * _RemoveFromClientQ
  49. * Description:
  50. * Removes a client context from the list
  51. * Arguments:
  52. * pClient - the client context
  53. * Return value:
  54. * TRUE on success
  55. * Called by:
  56. * SCDisconnect
  57. --*/
  58. BOOL _RemoveFromClientQ(PCONNECTINFO pClient)
  59. {
  60. PCONNECTINFO pIter, pPrev = NULL;
  61. EnterCriticalSection(g_lpcsGuardWaitQueue);
  62. pIter = g_pClientQHead;
  63. while (pIter && pIter != pClient) {
  64. pPrev = pIter;
  65. pIter = pIter->pNext;
  66. }
  67. if (pIter) {
  68. if (!pPrev) g_pClientQHead = pIter->pNext;
  69. else pPrev->pNext = pIter->pNext;
  70. pIter->pNext = NULL;
  71. }
  72. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  73. return (pIter != NULL);
  74. }
  75. /*++
  76. * Function:
  77. * _SetClientDead
  78. * Description:
  79. * Marks a client context as dead
  80. * Arguments:
  81. * dwClientProcessId - ID for the client process
  82. * Return value:
  83. * TRUE on success
  84. * Called by:
  85. * _FeedbackWndProc within feedback thread
  86. --*/
  87. BOOL _SetClientDead(LONG_PTR lClientProcessId)
  88. {
  89. PCONNECTINFO pIter;
  90. EnterCriticalSection(g_lpcsGuardWaitQueue);
  91. pIter = g_pClientQHead;
  92. while (pIter && pIter->lProcessId != lClientProcessId)
  93. {
  94. pIter = pIter->pNext;
  95. }
  96. if (pIter) pIter->dead = TRUE;
  97. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  98. return (pIter != NULL);
  99. }
  100. /*++
  101. * Function:
  102. * _CheckIsAcceptable
  103. * Description:
  104. * Checks if we can accept feedback from this RDP client
  105. * i.e. if this client is member of the client queue
  106. * Arguments:
  107. * dwProcessId - clients process Id
  108. * Return value:
  109. * Pointer to connection context. NULL if not found
  110. * Called by:
  111. * _FeedbackWndProc within feedback thread
  112. --*/
  113. PCONNECTINFO _CheckIsAcceptable(LONG_PTR lProcessId, BOOL bRClxType)
  114. {
  115. PCONNECTINFO pIter;
  116. EnterCriticalSection(g_lpcsGuardWaitQueue);
  117. pIter = g_pClientQHead;
  118. while(pIter &&
  119. (pIter->lProcessId != lProcessId || pIter->RClxMode != bRClxType))
  120. {
  121. pIter = pIter->pNext;
  122. }
  123. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  124. return (pIter);
  125. }
  126. /*++
  127. * Function:
  128. * _AddStrToClientBuffer
  129. * Description:
  130. * Add a string to the clients history buffer
  131. * When smclient calls Wait4Str it first checks that buffer
  132. * Arguments:
  133. * str - the string
  134. * dwProcessId - the client process Id
  135. * Called by:
  136. * _CheckForWaitingWorker
  137. --*/
  138. VOID _AddStrToClientBuffer(LPCWSTR str, LONG_PTR lProcessId)
  139. {
  140. PCONNECTINFO pIter;
  141. EnterCriticalSection(g_lpcsGuardWaitQueue);
  142. pIter = g_pClientQHead;
  143. while(pIter && pIter->lProcessId != lProcessId)
  144. {
  145. pIter = pIter->pNext;
  146. }
  147. if (pIter)
  148. {
  149. int strsize = wcslen(str);
  150. if (strsize >= MAX_STRING_LENGTH) strsize = MAX_STRING_LENGTH-1;
  151. wcsncpy( pIter->Feedback[pIter->nFBend],
  152. str,
  153. strsize);
  154. pIter->Feedback[pIter->nFBend][strsize] = 0;
  155. pIter->nFBend++;
  156. pIter->nFBend %= FEEDBACK_SIZE;
  157. if (pIter->nFBsize < FEEDBACK_SIZE)
  158. pIter->nFBsize++;
  159. }
  160. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  161. }
  162. /*
  163. *
  164. * WaitQ functions
  165. *
  166. */
  167. /*++
  168. * Function:
  169. * _AddToWaitQNoCheck
  170. * Description:
  171. * Adds an waiting event to the list with checking in the history list
  172. * Arguments:
  173. * pCI - client context
  174. * pWait - the event
  175. * Called by:
  176. * RegisterChat
  177. --*/
  178. VOID _AddToWaitQNoCheck(PCONNECTINFO pCI, PWAIT4STRING pWait)
  179. {
  180. ASSERT(pCI);
  181. EnterCriticalSection(g_lpcsGuardWaitQueue);
  182. pWait->pNext = g_pWaitQHead;
  183. g_pWaitQHead = pWait;
  184. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  185. }
  186. /*++
  187. * Function:
  188. * _AddToWaitQueue
  189. * Description:
  190. * Add an event to the list. If the event is waiting for string(s)
  191. * the history buffer is checked first
  192. * Arguments:
  193. * pCI - client context
  194. * pWait - the event
  195. * Called by:
  196. * _WaitSomething
  197. --*/
  198. VOID _AddToWaitQueue(PCONNECTINFO pCI, PWAIT4STRING pWait)
  199. {
  200. BOOL bDone = FALSE;
  201. int i, strn;
  202. ASSERT(pCI);
  203. // exit if we are dead
  204. if (/*!pWait->waitstr[0] && */pCI->dead)
  205. {
  206. SetEvent(pWait->evWait);
  207. goto exitpt;
  208. }
  209. EnterCriticalSection(g_lpcsGuardWaitQueue);
  210. // Check if we're already received this feedback
  211. if (pWait->WaitType == WAIT_STRING)
  212. // look if the string already came
  213. for(i = 0; !bDone && i < pCI->nFBsize; i++)
  214. {
  215. strn = (FEEDBACK_SIZE + pCI->nFBend - i - 1) % FEEDBACK_SIZE;
  216. if (!pCI->Feedback[strn][0]) continue;
  217. bDone = (wcsstr(pCI->Feedback[strn], pWait->waitstr) != NULL);
  218. }
  219. // In case of waiting multiple strings
  220. else if (pWait->WaitType == WAIT_MSTRINGS)
  221. {
  222. for(i = 0; !bDone && i < pCI->nFBsize; i++)
  223. {
  224. WCHAR *wszComp = pWait->waitstr;
  225. WCHAR *wszLast = pWait->waitstr + pWait->strsize;
  226. int idx = 0;
  227. strn = (FEEDBACK_SIZE + pCI->nFBend - i - 1) % FEEDBACK_SIZE;
  228. if (!pCI->Feedback[strn][0]) continue;
  229. while (wszComp < wszLast && *wszComp && !bDone)
  230. {
  231. if (wcsstr(pCI->Feedback[strn], wszComp))
  232. {
  233. int i;
  234. // Save the string
  235. for(i = 0; wszComp[i]; i++)
  236. pCI->szWait4MultipleStrResult[i] = (char)wszComp[i];
  237. // and the index
  238. pCI->szWait4MultipleStrResult[i] = 0;
  239. pCI->nWait4MultipleStrResult = idx;
  240. bDone = TRUE;
  241. }
  242. else
  243. {
  244. // Advance to next string
  245. wszComp += wcslen(wszComp) + 1;
  246. idx ++;
  247. }
  248. }
  249. }
  250. }
  251. else if (pWait->WaitType == WAIT_CLIPBOARD &&
  252. pWait->pOwner->bRClxClipboardReceived)
  253. {
  254. bDone = TRUE;
  255. }
  256. else if (pWait->WaitType == WAIT_DATA &&
  257. pWait->pOwner->pRClxDataChain)
  258. {
  259. bDone = TRUE;
  260. }
  261. // The string (or anything else) is in the history list
  262. // Set the event
  263. if (bDone)
  264. {
  265. SetEvent(pWait->evWait);
  266. pCI->nFBsize = pCI->nFBend = 0;
  267. }
  268. pWait->pNext = g_pWaitQHead;
  269. g_pWaitQHead = pWait;
  270. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  271. exitpt:
  272. ;
  273. }
  274. /*++
  275. * Function:
  276. * _RemoveFromWaitQueue
  277. * Description:
  278. * Removes an event from the list
  279. * Arguments:
  280. * pWait - the event
  281. * Return value:
  282. * TRUE if the event is found and removed
  283. * Called by:
  284. * _WaitSomething, _RemoveFromWaitQIndirect
  285. --*/
  286. BOOL _RemoveFromWaitQueue(PWAIT4STRING pWait)
  287. {
  288. PWAIT4STRING pIter, pPrev = NULL;
  289. EnterCriticalSection(g_lpcsGuardWaitQueue);
  290. pIter = g_pWaitQHead;
  291. while (pIter && pIter != pWait) {
  292. pPrev = pIter;
  293. pIter = pIter->pNext;
  294. }
  295. if (pIter) {
  296. if (!pPrev) g_pWaitQHead = pIter->pNext;
  297. else pPrev->pNext = pIter->pNext;
  298. pIter->pNext = NULL;
  299. }
  300. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  301. return (pIter != NULL);
  302. }
  303. /*++
  304. * Function:
  305. * _RemoveFromWaitQIndirect
  306. * Description:
  307. * Same as _RemoveFromWaitQueue but identifies the event
  308. * by client context and waited string
  309. * Arguments:
  310. * pCI - the client context
  311. * lpszWait4 - the string
  312. * Return value:
  313. * the event
  314. * Called by:
  315. * UnregisterChat
  316. --*/
  317. PWAIT4STRING _RemoveFromWaitQIndirect(PCONNECTINFO pCI, LPCWSTR lpszWait4)
  318. {
  319. PWAIT4STRING pIter;
  320. ASSERT(pCI);
  321. // Search the list
  322. EnterCriticalSection(g_lpcsGuardWaitQueue);
  323. pIter = g_pWaitQHead;
  324. while (pIter &&
  325. (pIter->pOwner != pCI ||
  326. wcscmp(pIter->waitstr, lpszWait4))
  327. )
  328. pIter = pIter->pNext;
  329. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  330. if (pIter)
  331. {
  332. _RemoveFromWaitQueue(pIter);
  333. }
  334. return pIter;
  335. }
  336. /*++
  337. * Function:
  338. * _RetrieveFromWaitQByEvent
  339. * Description:
  340. * Searches the waiting list by event handler
  341. * Arguments:
  342. * hEvent - the handler
  343. * Return value:
  344. * The event structure
  345. * Called by:
  346. * _WaitSomething when responds on chat sequence
  347. --*/
  348. PWAIT4STRING _RetrieveFromWaitQByEvent(HANDLE hEvent)
  349. {
  350. PWAIT4STRING pIter;
  351. EnterCriticalSection(g_lpcsGuardWaitQueue);
  352. pIter = g_pWaitQHead;
  353. while (pIter &&
  354. pIter->evWait != hEvent)
  355. pIter = pIter->pNext;
  356. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  357. return pIter;
  358. }
  359. /*++
  360. * Function:
  361. * _RetrieveFromWaitQByOwner
  362. * Description:
  363. * Searches the waiting list by owner record
  364. * Arguments:
  365. * pCI - pointer to the owner context
  366. * Return value:
  367. * The event structure
  368. * Called by:
  369. * RClx_MsgReceived
  370. --*/
  371. PWAIT4STRING
  372. _RetrieveFromWaitQByOwner(PCONNECTINFO pCI)
  373. {
  374. PWAIT4STRING pIter;
  375. EnterCriticalSection(g_lpcsGuardWaitQueue);
  376. pIter = g_pWaitQHead;
  377. while (pIter &&
  378. pIter->pOwner != pCI)
  379. pIter = pIter->pNext;
  380. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  381. return pIter;
  382. }
  383. /*++
  384. * Function:
  385. * _FlushFromWaitQ
  386. * Description:
  387. * Flush everithing that we are waiting for from the list
  388. * the client is going to DIE
  389. * Arguments:
  390. * pCI - client context
  391. * Called by:
  392. * _CloseConnectInfo
  393. --*/
  394. VOID _FlushFromWaitQ(PCONNECTINFO pCI)
  395. {
  396. PWAIT4STRING pIter, pPrev, pNext;
  397. ASSERT(pCI);
  398. pPrev = NULL;
  399. EnterCriticalSection(g_lpcsGuardWaitQueue);
  400. pIter = g_pWaitQHead;
  401. do {
  402. while (pIter && pIter->pOwner != pCI) {
  403. pPrev = pIter;
  404. pIter = pIter->pNext;
  405. }
  406. if (pIter) {
  407. if (!pPrev) g_pWaitQHead = pIter->pNext;
  408. else pPrev->pNext = pIter->pNext;
  409. pNext = pIter->pNext;
  410. pIter->pNext = NULL;
  411. // Important stuff
  412. if (pIter->evWait)
  413. CloseHandle(pIter->evWait);
  414. free(pIter);
  415. pIter = pNext;
  416. }
  417. } while (pIter);
  418. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  419. }
  420. /*++
  421. * Function:
  422. * _CheckForWaitingWorker
  423. * Description:
  424. * Check the received string against the waited events
  425. * Arguments:
  426. * wszFeed - the received string
  427. * dwProcessId - Id of the sender
  428. * Return value:
  429. * TRUE if an event is found and signaled
  430. * Called by:
  431. * _TextOutReceived, _GlyphReceived
  432. --*/
  433. BOOL _CheckForWaitingWorker(LPCWSTR wszFeed, LONG_PTR lProcessId)
  434. {
  435. PWAIT4STRING pIter;
  436. BOOL bRun;
  437. CHAR szBuff[ MAX_STRING_LENGTH ];
  438. CHAR *szPBuff;
  439. DWORD dwBuffLen;
  440. LPCWSTR wszPFeed;
  441. if ( NULL != g_pfnPrintMessage )
  442. {
  443. wszPFeed = wszFeed;
  444. while ( *wszPFeed )
  445. {
  446. if ( (unsigned short)(*wszPFeed) > 0xff )
  447. break;
  448. wszPFeed ++;
  449. }
  450. if ( *wszPFeed )
  451. {
  452. szBuff[0] = '\\';
  453. szBuff[1] = 'u';
  454. szPBuff = szBuff + 2;
  455. wszPFeed = wszFeed;
  456. dwBuffLen = MAX_STRING_LENGTH - 3;
  457. while ( 4 <= dwBuffLen &&
  458. 0 != *wszPFeed)
  459. {
  460. DWORD dwLen;
  461. if ( dwBuffLen < 4 )
  462. break;
  463. dwLen = _snprintf( szPBuff, dwBuffLen + 1, "%02x",
  464. (BYTE)((*wszPFeed) & 0xff ));
  465. szPBuff += dwLen;
  466. dwBuffLen -= dwLen;
  467. dwLen = _snprintf( szPBuff, dwBuffLen + 1, "%02x",
  468. (BYTE)(((*wszPFeed) >> 8) & 0xff ));
  469. szPBuff += dwLen;
  470. dwBuffLen -= dwLen;
  471. wszPFeed ++;
  472. }
  473. *szPBuff = 0;
  474. TRACE((ALIVE_MESSAGE, "Received: %s\n", szBuff));
  475. } else {
  476. TRACE((ALIVE_MESSAGE, "Received: %S\n", wszFeed));
  477. }
  478. }
  479. _AddStrToClientBuffer(wszFeed, lProcessId);
  480. EnterCriticalSection(g_lpcsGuardWaitQueue);
  481. pIter = g_pWaitQHead;
  482. bRun = TRUE;
  483. while(pIter && bRun)
  484. {
  485. if (pIter->lProcessId == lProcessId)
  486. {
  487. // Check for expected string (one)
  488. if (pIter->WaitType == WAIT_STRING &&
  489. wcsstr(wszFeed, pIter->waitstr))
  490. bRun = FALSE;
  491. else
  492. // Check for expected strings (many)
  493. if (pIter->WaitType == WAIT_MSTRINGS)
  494. {
  495. WCHAR *wszComp = pIter->waitstr;
  496. WCHAR *wszLast = pIter->waitstr + pIter->strsize;
  497. int idx = 0;
  498. while (wszComp < wszLast && *wszComp && bRun)
  499. {
  500. if (wcsstr(wszFeed, wszComp))
  501. {
  502. int i;
  503. PCONNECTINFO pOwner = pIter->pOwner;
  504. // Save the string
  505. for(i = 0; wszComp[i]; i++)
  506. pOwner->szWait4MultipleStrResult[i] = (char)wszComp[i];
  507. pOwner->szWait4MultipleStrResult[i] = 0;
  508. pOwner->nWait4MultipleStrResult = idx;
  509. bRun = FALSE;
  510. }
  511. else
  512. {
  513. // Advance to next string
  514. wszComp += wcslen(wszComp) + 1;
  515. idx ++;
  516. }
  517. }
  518. }
  519. }
  520. // Advance to the next pointer
  521. if (bRun)
  522. pIter = pIter->pNext;
  523. }
  524. if (pIter)
  525. {
  526. SetEvent(pIter->evWait);
  527. }
  528. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  529. return (pIter != NULL);
  530. }
  531. /*++
  532. * Function:
  533. * _TextOutReceived
  534. * Description:
  535. * TextOut order is received from the client, the string is
  536. * in shared memory. Unmaps the memory and checks if the
  537. * strings is waited by anybody. Also adds the string
  538. * to the client history buffer
  539. * Arguments:
  540. * dwProcessId - senders Id
  541. * hMapF - handle to shared memory, which contains the string
  542. * Return value:
  543. * TRUE if a client is found and signaled
  544. * Called by:
  545. * _FeedbackWndProc within feedback thread
  546. --*/
  547. BOOL _TextOutReceived(LONG_PTR lProcessId, HANDLE hMapF)
  548. {
  549. PFEEDBACKINFO pView;
  550. PCONNECTINFO pIterCl;
  551. HANDLE hDupMapF;
  552. BOOL rv = FALSE;
  553. EnterCriticalSection(g_lpcsGuardWaitQueue);
  554. pIterCl = g_pClientQHead;
  555. while(pIterCl && pIterCl->lProcessId != lProcessId)
  556. pIterCl = pIterCl->pNext;
  557. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  558. if (!pIterCl)
  559. goto exitpt;
  560. if (!DuplicateHandle(pIterCl->hProcess,
  561. hMapF,
  562. GetCurrentProcess(),
  563. &hDupMapF,
  564. FILE_MAP_READ,
  565. FALSE,
  566. 0))
  567. {
  568. TRACE((ERROR_MESSAGE,
  569. "TEXTOUT:Can't dup file handle, GetLastError = %d\n",
  570. GetLastError()));
  571. goto exitpt;
  572. }
  573. pView = MapViewOfFile(hDupMapF,
  574. FILE_MAP_READ,
  575. 0,
  576. 0,
  577. sizeof(*pView));
  578. if (!pView)
  579. {
  580. TRACE((ERROR_MESSAGE,
  581. "TEXTOUT:Can't map a view, GetLastError = %d\n",
  582. GetLastError()));
  583. goto exitpt1;
  584. }
  585. rv = _CheckForWaitingWorker(pView->string, lProcessId);
  586. exitpt1:
  587. UnmapViewOfFile(pView);
  588. CloseHandle(hDupMapF);
  589. exitpt:
  590. return rv;
  591. }
  592. /*++
  593. * Function:
  594. * _GlyphReceived
  595. * Description:
  596. * Same as _TextOutReceived but for GlyphOut order
  597. * the glyph is in shared memory. It is converted to
  598. * string by calling Glyph2String!bmpcache.c
  599. * Arguments:
  600. * dwProcessId - senders Id
  601. * hMapF - handle to shared memory
  602. * Return value:
  603. * TRUE if a client is found and signaled
  604. * Called by:
  605. * _FeedbackWndProc within feedback thread
  606. --*/
  607. BOOL _GlyphReceived(LONG_PTR lProcessId, HANDLE hMapF)
  608. {
  609. WCHAR wszFeed[MAX_STRING_LENGTH];
  610. BOOL rv = FALSE;
  611. PBMPFEEDBACK pView;
  612. PCONNECTINFO pIterCl;
  613. HANDLE hDupMapF;
  614. UINT nSize;
  615. EnterCriticalSection(g_lpcsGuardWaitQueue);
  616. pIterCl = g_pClientQHead;
  617. while(pIterCl && pIterCl->lProcessId != lProcessId)
  618. pIterCl = pIterCl->pNext;
  619. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  620. if (!pIterCl)
  621. goto exitpt;
  622. if (!DuplicateHandle( pIterCl->hProcess,
  623. hMapF,
  624. GetCurrentProcess(),
  625. &hDupMapF,
  626. FILE_MAP_READ,
  627. FALSE,
  628. 0))
  629. {
  630. TRACE((ERROR_MESSAGE,
  631. "GLYPH:Can't dup file handle, GetLastError = %d\n",
  632. GetLastError()));
  633. goto exitpt;
  634. }
  635. pView = MapViewOfFile(hDupMapF,
  636. FILE_MAP_READ,
  637. 0,
  638. 0,
  639. sizeof(*pView));
  640. if (!pView)
  641. {
  642. TRACE((ERROR_MESSAGE,
  643. "GLYPH:Can't map a view, GetLastError = %d\n",
  644. GetLastError()));
  645. goto exitpt1;
  646. }
  647. // Get bitmap size
  648. nSize = pView->bmpsize;
  649. if (!nSize)
  650. goto exitpt1;
  651. // unmap
  652. UnmapViewOfFile(pView);
  653. // remap the whole structure
  654. pView = MapViewOfFile(hDupMapF,
  655. FILE_MAP_READ,
  656. 0,
  657. 0,
  658. sizeof(*pView) + nSize);
  659. if (!pView)
  660. {
  661. TRACE((ERROR_MESSAGE,
  662. "GLYPH:Can't map a view, GetLastError = %d\n",
  663. GetLastError()));
  664. goto exitpt1;
  665. }
  666. if (!Glyph2String(pView, wszFeed, sizeof(wszFeed)/sizeof(WCHAR)))
  667. {
  668. goto exitpt1;
  669. } else {
  670. }
  671. rv = _CheckForWaitingWorker(wszFeed, lProcessId);
  672. exitpt1:
  673. UnmapViewOfFile(pView);
  674. CloseHandle(hDupMapF);
  675. exitpt:
  676. return rv;
  677. }
  678. /*++
  679. * Function:
  680. * _CheckForWorkerWaitingDisconnect
  681. * Description:
  682. * Signals a worker (client thread) wich waits for a disconnect event
  683. * Arguments:
  684. * dwProcessId - clients Id
  685. * Return value:
  686. * TRUE if a client is found and signaled
  687. * Called by:
  688. * _FeedbackWndProc within feedback thread
  689. --*/
  690. BOOL _CheckForWorkerWaitingDisconnect(LONG_PTR lProcessId)
  691. {
  692. PWAIT4STRING pIter;
  693. EnterCriticalSection(g_lpcsGuardWaitQueue);
  694. pIter = g_pWaitQHead;
  695. while(pIter &&
  696. (pIter->WaitType != WAIT_DISC ||
  697. pIter->lProcessId != lProcessId))
  698. {
  699. pIter = pIter->pNext;
  700. }
  701. if (pIter)
  702. {
  703. SetEvent(pIter->evWait);
  704. }
  705. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  706. return (pIter != NULL);
  707. }
  708. /*++
  709. * Function:
  710. * _CheckForWorkerWaitingConnect
  711. * Description:
  712. * Signals a worker waiting for a connection
  713. * Arguments:
  714. * hwndClient - clients window handle, this is needed for
  715. * sending messages to the client
  716. * dwProcessId - client Id
  717. * Return value:
  718. * TRUE if a client is found and signaled
  719. * Called by:
  720. * _FeedbackWndProc within feedback thread
  721. --*/
  722. BOOL _CheckForWorkerWaitingConnect(HWND hwndClient, LONG_PTR lProcessId)
  723. {
  724. PWAIT4STRING pIter;
  725. EnterCriticalSection(g_lpcsGuardWaitQueue);
  726. pIter = g_pWaitQHead;
  727. while(pIter &&
  728. (pIter->WaitType != WAIT_CONN ||
  729. pIter->lProcessId != lProcessId))
  730. {
  731. pIter = pIter->pNext;
  732. }
  733. if (pIter)
  734. {
  735. PCONNECTINFO pOwner = pIter->pOwner;
  736. if (pOwner)
  737. pOwner->hClient = hwndClient;
  738. else
  739. TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
  740. SetEvent(pIter->evWait);
  741. }
  742. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  743. return (pIter != NULL);
  744. }
  745. /*++
  746. * Function:
  747. * _CheckForWorkerWaitingConnectAndSetId
  748. * Description:
  749. * This is intended for RCLX mode. dwProcessId is zero
  750. * so this function look for such a client and sets its dwProcessId
  751. * Signals a worker waiting for a connection
  752. * Arguments:
  753. * hwndClient - clients window handle, this is needed for
  754. * sending messages to the client
  755. * dwProcessId - client Id
  756. * Return value:
  757. * connection context, NULL if not found
  758. * Called by:
  759. * _FeedbackWndProc within feedback thread
  760. --*/
  761. PCONNECTINFO
  762. _CheckForWorkerWaitingConnectAndSetId(HWND hwndClient, LONG_PTR lProcessId)
  763. {
  764. PWAIT4STRING pIter;
  765. PCONNECTINFO pOwner = NULL;
  766. EnterCriticalSection(g_lpcsGuardWaitQueue);
  767. pIter = g_pWaitQHead;
  768. while(pIter &&
  769. (pIter->WaitType != WAIT_CONN ||
  770. pIter->lProcessId))
  771. {
  772. pIter = pIter->pNext;
  773. }
  774. if (pIter)
  775. {
  776. pOwner = pIter->pOwner;
  777. if (pOwner)
  778. {
  779. ASSERT(pOwner->RClxMode);
  780. pOwner->hClient = hwndClient;
  781. pOwner->lProcessId = lProcessId;
  782. pIter->lProcessId = lProcessId; // Disable next lookup in
  783. // the same entry
  784. }
  785. else
  786. TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
  787. SetEvent(pIter->evWait);
  788. }
  789. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  790. return (pOwner);
  791. }
  792. /*++
  793. * Function:
  794. * _CheckForWorkerWaitingReconnectAndSetNewId
  795. * Description:
  796. * This is intended for RCLX mode. When mstsc wants to reconnect
  797. * looks for dwLookupId as an ID to reconnect
  798. * then sets the new ID
  799. * then gets
  800. * Arguments:
  801. * hwndClient - clients window handle, this is needed for
  802. * sending messages to the client
  803. * dwLookupId, dwNewId
  804. * Return value:
  805. * connection context, NULL if not found
  806. * Called by:
  807. * _FeedbackWndProc within feedback thread
  808. --*/
  809. PCONNECTINFO
  810. _CheckForWorkerWaitingReconnectAndSetNewId(
  811. HWND hwndClient,
  812. DWORD dwLookupId,
  813. LONG_PTR lNewId)
  814. {
  815. PWAIT4STRING pIter;
  816. PCONNECTINFO pOwner = NULL;
  817. EnterCriticalSection(g_lpcsGuardWaitQueue);
  818. pIter = g_pWaitQHead;
  819. while(pIter &&
  820. (pIter->WaitType != WAIT_CONN ||
  821. !pIter->pOwner ||
  822. pIter->pOwner->dwThreadId != dwLookupId ||
  823. !(pIter->pOwner->bWillCallAgain)))
  824. {
  825. pIter = pIter->pNext;
  826. }
  827. if (pIter)
  828. {
  829. pOwner = pIter->pOwner;
  830. if (pOwner)
  831. {
  832. ASSERT(pOwner->RClxMode);
  833. pOwner->hClient = hwndClient;
  834. pOwner->lProcessId = lNewId;
  835. pIter->lProcessId = lNewId; // Disable next lookup in
  836. // the same entry
  837. pOwner->bWillCallAgain = FALSE;
  838. }
  839. else
  840. TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
  841. SetEvent(pIter->evWait);
  842. }
  843. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  844. return (pOwner);
  845. }
  846. /*++
  847. * Function:
  848. * _CancelWaitingWorker
  849. * Description:
  850. * Releases a worker waiting for any event.
  851. * Eventualy the client is disconnected
  852. * Arguments:
  853. * dwProcessId - client Id
  854. * Return value:
  855. * TRUE if a client is found and signaled
  856. * Called by:
  857. * _FeedbackWndProc within feedback thread
  858. --*/
  859. BOOL _CancelWaitingWorker(LONG_PTR lProcessId)
  860. {
  861. PWAIT4STRING pIter;
  862. EnterCriticalSection(g_lpcsGuardWaitQueue);
  863. pIter = g_pWaitQHead;
  864. while(pIter &&
  865. pIter->lProcessId != lProcessId)
  866. {
  867. pIter = pIter->pNext;
  868. }
  869. if (pIter)
  870. {
  871. SetEvent(pIter->evWait);
  872. }
  873. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  874. return (pIter != NULL);
  875. }
  876. /*++
  877. * Function:
  878. * _CheckForWorkerWaitingClipboard
  879. * Description:
  880. * Releases a worker waiting for client's clipboard content.
  881. * Arguments:
  882. * dwProcessId - client Id
  883. * Return value:
  884. * TRUE if a client is found and signaled
  885. * Called by:
  886. * _FeedbackWndProc within feedback thread
  887. --*/
  888. BOOL _CheckForWorkerWaitingClipboard(
  889. PCONNECTINFO pRClxOwner,
  890. UINT uiFormat,
  891. UINT nSize,
  892. PVOID pClipboard,
  893. LONG_PTR lProcessId)
  894. {
  895. PWAIT4STRING pIter = NULL;
  896. HGLOBAL ghNewClipboard = NULL;
  897. LPVOID pNewClipboard = NULL;
  898. ASSERT(pRClxOwner);
  899. TRACE((ALIVE_MESSAGE, "Clipboard received, FormatID=%d, Size=%d\n",
  900. uiFormat, nSize));
  901. if (nSize)
  902. {
  903. // Copy the clipboard content to new buffer
  904. ghNewClipboard = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, nSize);
  905. if (!ghNewClipboard)
  906. {
  907. TRACE((ERROR_MESSAGE, "_CheckForWorkerWaitingClipboard: can't allocate %d bytes\n", nSize));
  908. goto exitpt;
  909. }
  910. pNewClipboard = GlobalLock(ghNewClipboard);
  911. if (!pNewClipboard)
  912. {
  913. TRACE((ERROR_MESSAGE, "_CheckForWorkerWaitingClipboard: can't lock global memory\n"));
  914. goto exitpt;
  915. }
  916. memcpy(pNewClipboard, pClipboard, nSize);
  917. // Unlock the clipboard buffer
  918. GlobalUnlock(ghNewClipboard);
  919. pNewClipboard = NULL;
  920. } else {
  921. pClipboard = NULL;
  922. }
  923. EnterCriticalSection(g_lpcsGuardWaitQueue);
  924. pIter = g_pWaitQHead;
  925. while(pIter &&
  926. (pIter->lProcessId != lProcessId ||
  927. pIter->WaitType != WAIT_CLIPBOARD))
  928. {
  929. pIter = pIter->pNext;
  930. }
  931. if (pIter)
  932. {
  933. PCONNECTINFO pOwner = pIter->pOwner;
  934. // Put the buffer in the worker's context
  935. if (pOwner)
  936. {
  937. ASSERT(pOwner->RClxMode);
  938. ASSERT(pOwner == pRClxOwner);
  939. // pOwner->ghClipboard should be NULL
  940. ASSERT(pOwner->ghClipboard == NULL);
  941. pOwner->ghClipboard = ghNewClipboard;
  942. pOwner->uiClipboardFormat = uiFormat;
  943. pOwner->nClipboardSize = nSize;
  944. }
  945. else
  946. TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
  947. SetEvent(pIter->evWait);
  948. } else {
  949. // Can't find anybody waiting, add it to the context owner
  950. pRClxOwner->ghClipboard = ghNewClipboard;
  951. pRClxOwner->uiClipboardFormat = uiFormat;
  952. pRClxOwner->nClipboardSize = nSize;
  953. }
  954. pRClxOwner->bRClxClipboardReceived = TRUE;
  955. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  956. exitpt:
  957. if (!pIter)
  958. // worker not found, clear the allocated buffer
  959. {
  960. if (ghNewClipboard)
  961. GlobalFree(ghNewClipboard);
  962. }
  963. return (pIter != NULL);
  964. }
  965. BOOL
  966. _SetSessionID(LONG_PTR lProcessId, UINT uSessionId)
  967. {
  968. PCONNECTINFO pIter, pPrev = NULL;
  969. EnterCriticalSection(g_lpcsGuardWaitQueue);
  970. pIter = g_pClientQHead;
  971. while (pIter &&
  972. pIter->lProcessId != lProcessId)
  973. pIter = pIter->pNext;
  974. if (pIter)
  975. pIter->uiSessionId = (uSessionId)?uSessionId:-1;
  976. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  977. return (pIter != NULL);
  978. }