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.

1272 lines
35 KiB

  1. /*++
  2. * File name:
  3. * rclx.c
  4. * Contents:
  5. * A module for communicating with clxtshar via TCP/IP
  6. * RCLX (Remote CLient eXecution) implemetation
  7. *
  8. * Copyright (C) 1998-1999 Microsoft Corp.
  9. --*/
  10. #include <windows.h>
  11. #include <winsock.h>
  12. #include <malloc.h>
  13. #include <stdio.h>
  14. #include "tclient.h"
  15. #define PROTOCOLAPI __declspec(dllexport)
  16. #include "protocol.h"
  17. #include "gdata.h"
  18. #include "queues.h"
  19. #include "misc.h"
  20. #include "bmpcache.h"
  21. #include "rclx.h"
  22. #include "extraexp.h"
  23. /*
  24. * Globals
  25. */
  26. u_short g_nPortNumber = RCLX_DEFAULT_PORT; // Default port to listen
  27. SOCKET g_hSrvSocket = INVALID_SOCKET; // Socket to listen to
  28. PRCLXCONTEXT g_pRClxList = NULL; // Linked list of all connections
  29. // which havn't receive
  30. // client info
  31. #ifndef SD_RECEIVE
  32. #define SD_RECEIVE 0x00
  33. #define SD_SEND 0x01
  34. #define SD_BOTH 0x02
  35. #endif // SD_RECEIVE
  36. SOCKET RClx_Listen(u_short nPortNumber);
  37. VOID RClx_CloseSocket(SOCKET hSocket);
  38. VOID _RClx_RemoveContextFromGlobalQueue(PRCLXCONTEXT pContext);
  39. /*++
  40. * Function:
  41. * RClx_Init
  42. * Description:
  43. * Module initialization. Calls WSAStartup, creates a listening
  44. * on wich to listen to. Selects FD_ACCEPT as event passed to
  45. * the feedback thread/window
  46. * Return value:
  47. * TRUE on success
  48. * Called by:
  49. * tclient.c:InitDone
  50. --*/
  51. BOOL RClx_Init(VOID)
  52. {
  53. WORD versionRequested;
  54. WSADATA wsaData;
  55. INT intRC;
  56. BOOL rv = FALSE;
  57. versionRequested = MAKEWORD(1, 1);
  58. intRC = WSAStartup(versionRequested, &wsaData);
  59. if (intRC != 0)
  60. {
  61. TRACE((ERROR_MESSAGE,
  62. "Failed to initialize WinSock rc:%d\n",
  63. intRC));
  64. printf("Failed to initialize WinSock rc:%d\n", intRC);
  65. goto exitpt;
  66. }
  67. g_hSrvSocket = RClx_Listen(g_nPortNumber);
  68. if (g_hSrvSocket == INVALID_SOCKET)
  69. {
  70. TRACE((ERROR_MESSAGE,
  71. "Can't bind on port: %d\n",
  72. g_nPortNumber));
  73. printf("Can't bind on port: %d\n",
  74. g_nPortNumber);
  75. goto exitpt;
  76. }
  77. rv = TRUE;
  78. exitpt:
  79. return rv;
  80. }
  81. /*++
  82. * Function:
  83. * RClx_Done
  84. * Description:
  85. * Destruction of the module. Closes the listening socket and
  86. * winsocket library
  87. * Called by:
  88. * tclient.c:InitDone
  89. --*/
  90. VOID RClx_Done(VOID)
  91. {
  92. PRCLXCONTEXT pRClxIter;
  93. // g_pRClxList cleanup
  94. pRClxIter = g_pRClxList;
  95. while (pRClxIter)
  96. {
  97. RClx_EndRecv(pRClxIter);
  98. pRClxIter = pRClxIter->pNext;
  99. }
  100. if (g_hSrvSocket)
  101. closesocket(g_hSrvSocket);
  102. WSACleanup();
  103. }
  104. /*++
  105. * Function:
  106. * RClx_Listen
  107. * Description:
  108. * Creates a socket on wich to listen for incoming connections from
  109. * clxtshar.dll. Selects the feedback window/thread as a dispatcher
  110. * of FD_ACCEPT events, i.e RClx_DispatchWSockEvent will be called
  111. * when winsock event occured
  112. * Arguments:
  113. * nPortNumber - port to listen to
  114. * Return value:
  115. * INVALID_SOCKET on error, or valid SOCKET of the listening port
  116. * Called by:
  117. * RClx_Init
  118. --*/
  119. SOCKET RClx_Listen(u_short nPortNumber)
  120. {
  121. struct sockaddr_in sin;
  122. INT optval = 1;
  123. SOCKET hSocket;
  124. ASSERT(g_nPortNumber);
  125. hSocket = socket(AF_INET, SOCK_STREAM, 0);
  126. if (hSocket == INVALID_SOCKET)
  127. {
  128. TRACE((ERROR_MESSAGE, "Can't create socket: %d\n", WSAGetLastError()));
  129. printf("Can't create socket: %d\n", WSAGetLastError());
  130. goto exitpt;
  131. }
  132. setsockopt(hSocket, // Don't linger on socket close
  133. IPPROTO_TCP,
  134. TCP_NODELAY,
  135. (const char *)&optval,
  136. sizeof(optval));
  137. setsockopt(hSocket,
  138. SOL_SOCKET,
  139. SO_DONTLINGER,
  140. (const char *)&optval,
  141. sizeof(optval));
  142. memset(&sin, 0, sizeof(sin));
  143. sin.sin_family = PF_INET;
  144. sin.sin_port = htons(nPortNumber);
  145. sin.sin_addr.s_addr = INADDR_ANY;
  146. if (bind(hSocket, (SOCKADDR *)&sin, sizeof(sin)) == SOCKET_ERROR)
  147. {
  148. TRACE((ERROR_MESSAGE, "Can't bind: %d\n", WSAGetLastError()));
  149. printf("Can't bind: %d\n", WSAGetLastError());
  150. closesocket(hSocket);
  151. hSocket = INVALID_SOCKET;
  152. goto exitpt;
  153. }
  154. if (listen(hSocket, 5) == SOCKET_ERROR)
  155. {
  156. TRACE((ERROR_MESSAGE, "Can't listen: %d\n", WSAGetLastError()));
  157. printf("Can't listen: %d\n", WSAGetLastError());
  158. closesocket(hSocket);
  159. hSocket = INVALID_SOCKET;
  160. goto exitpt;
  161. }
  162. while(!g_hWindow)
  163. {
  164. Sleep(500); // Window is not created yet. Wait !
  165. }
  166. if (WSAAsyncSelect(hSocket, g_hWindow, WM_WSOCK, FD_ACCEPT) ==
  167. SOCKET_ERROR)
  168. {
  169. TRACE((ERROR_MESSAGE,
  170. "Can't \"select\" FD_ACCEPT on listening socket: %d\n",
  171. WSAGetLastError()));
  172. printf("Can't \"select\" FD_ACCEPT on listening socket: %d\n",
  173. WSAGetLastError());
  174. RClx_CloseSocket(hSocket);
  175. hSocket = INVALID_SOCKET;
  176. goto exitpt;
  177. }
  178. exitpt:
  179. return hSocket;
  180. }
  181. /*++
  182. * Function:
  183. * RClx_Accept
  184. * Description:
  185. * Accepts next connection from g_hSrvSocket
  186. * Return value:
  187. * INVALID_SOCKET on error, or valid SOCKET of the accepted connection
  188. * Called by:
  189. * RClx_DispatchWSockEvent upon FD_ACCEPT event
  190. --*/
  191. SOCKET RClx_Accept(VOID)
  192. {
  193. struct sockaddr_in sin;
  194. INT addrlen;
  195. SOCKET hClient;
  196. ASSERT(g_hSrvSocket != INVALID_SOCKET);
  197. addrlen = sizeof(sin);
  198. if ((hClient = accept(g_hSrvSocket,
  199. (struct sockaddr *)&sin,
  200. &addrlen)) ==
  201. INVALID_SOCKET)
  202. {
  203. if (WSAGetLastError() != WSAEWOULDBLOCK)
  204. TRACE((ERROR_MESSAGE,
  205. "Accept failed: %d\n",
  206. WSAGetLastError()));
  207. goto exitpt;
  208. }
  209. exitpt:
  210. return hClient;
  211. }
  212. /*++
  213. * Function:
  214. * RClx_StartRecv
  215. * Description:
  216. * Allocates and initializes context for a connection
  217. * Return value:
  218. * PRCLXCONTEXT - pointer to valid RCLX context or NULL on error
  219. * Called by:
  220. * RClx_DispatchWSockEvent upon FD_ACCEPT event
  221. --*/
  222. PRCLXCONTEXT RClx_StartRecv(VOID)
  223. {
  224. PRCLXCONTEXT pContext;
  225. pContext = malloc(sizeof(*pContext));
  226. if (!pContext)
  227. goto exitpt;
  228. memset(pContext, 0, sizeof(*pContext));
  229. exitpt:
  230. return pContext;
  231. }
  232. /*++
  233. * Function:
  234. * RClx_EndRecv
  235. * Description:
  236. * Frees all resources allocated within an RCLX context
  237. * and the context itself.
  238. * Becaus the RCLX context is kept in hClient member of CONNECTINFO
  239. * structure, the caller of this function have to zero pCI->hClient
  240. * Arguments:
  241. * pContext - an RCLX context
  242. * Called by:
  243. * RClx_DispatchWSockEvent upon FD_ACCEPT event when fail to
  244. * find waiting worker or
  245. * scfuncs.c:_CloseConnectionInfo
  246. --*/
  247. VOID RClx_EndRecv(PRCLXCONTEXT pContext)
  248. {
  249. ASSERT(pContext);
  250. if (pContext->pHead)
  251. {
  252. free(pContext->pHead);
  253. pContext->pHead = NULL;
  254. }
  255. if (pContext->pTail)
  256. {
  257. free(pContext->pTail);
  258. pContext->pTail = NULL;
  259. }
  260. if (pContext->hSocket && pContext->hSocket != INVALID_SOCKET)
  261. {
  262. RClx_CloseSocket(pContext->hSocket);
  263. }
  264. free(pContext);
  265. }
  266. /*++
  267. * Function:
  268. * RClx_Receive
  269. * Description:
  270. * RCLXCONTEXT contains a buffer for incoming message
  271. * this function trys to receive it all. If the socket blocks
  272. * the function exits with OK and next time FD_READ is received will
  273. * be called again. If a whole message is received pContext->bRecvDone
  274. * is set to TRUE. This is an indication that message arrived
  275. * Arguments:
  276. * pContext - RCLX context
  277. * Return value:
  278. * TRUE if everithing went OK. FALSE if socket must be closed
  279. * Called by:
  280. * RClx_DispatchWSockEvent upon FD_READ event
  281. --*/
  282. BOOL RClx_Receive(PRCLXCONTEXT pContext)
  283. {
  284. INT result = 0;
  285. SOCKET hSocket;
  286. ASSERT(pContext);
  287. hSocket = pContext->hSocket;
  288. ASSERT(hSocket != INVALID_SOCKET);
  289. do {
  290. if (!pContext->bPrologReceived)
  291. {
  292. // Receive the prolog
  293. result = recv(hSocket,
  294. ((BYTE *)&(pContext->Prolog)) +
  295. sizeof(pContext->Prolog) - pContext->nBytesToReceive,
  296. pContext->nBytesToReceive,
  297. 0);
  298. if (result != SOCKET_ERROR)
  299. {
  300. pContext->nBytesToReceive -= result;
  301. if (!pContext->nBytesToReceive)
  302. {
  303. pContext->bPrologReceived = TRUE;
  304. result = 1; // Hack, otherwise the loop can exit
  305. pContext->nBytesToReceive = pContext->Prolog.HeadSize;
  306. // Check if we have proper buffers allocated
  307. alloc_retry:
  308. if (pContext->Prolog.HeadSize)
  309. if (!pContext->pHead)
  310. pContext->pHead = malloc(pContext->Prolog.HeadSize);
  311. else if (pContext->Prolog.HeadSize >
  312. pContext->nHeadAllocated)
  313. pContext->pHead = realloc(pContext->pHead,
  314. pContext->Prolog.HeadSize);
  315. if (pContext->Prolog.TailSize)
  316. if (!pContext->pTail)
  317. pContext->pTail = malloc(pContext->Prolog.TailSize);
  318. else if (pContext->Prolog.TailSize >
  319. pContext->nTailAllocated)
  320. pContext->pTail = realloc(pContext->pTail,
  321. pContext->Prolog.TailSize);
  322. if ((pContext->Prolog.HeadSize && !pContext->pHead)
  323. ||
  324. (pContext->Prolog.TailSize && !pContext->pTail))
  325. {
  326. TRACE((WARNING_MESSAGE,
  327. "Can't (re)allocate memory. Sleep for a minute"));
  328. Sleep(60000);
  329. goto alloc_retry;
  330. } else {
  331. pContext->nHeadAllocated = pContext->Prolog.HeadSize;
  332. pContext->nTailAllocated = pContext->Prolog.TailSize;
  333. }
  334. }
  335. }
  336. } else if (!pContext->bHeadReceived)
  337. {
  338. // Receive the message head
  339. if (pContext->nBytesToReceive)
  340. result = recv(hSocket,
  341. ((BYTE *)pContext->pHead) +
  342. pContext->Prolog.HeadSize - pContext->nBytesToReceive,
  343. pContext->nBytesToReceive,
  344. 0);
  345. else
  346. result = 0;
  347. if (result != SOCKET_ERROR)
  348. {
  349. pContext->nBytesToReceive -= result;
  350. if (!pContext->nBytesToReceive)
  351. {
  352. pContext->bHeadReceived = TRUE;
  353. pContext->nBytesToReceive = pContext->Prolog.TailSize;
  354. result = 1; // Hack, otherwise the loop can exit
  355. }
  356. }
  357. } else {
  358. // Receive the message tail (actual info)
  359. if (pContext->nBytesToReceive)
  360. result = recv(hSocket,
  361. ((BYTE *)pContext->pTail) +
  362. pContext->Prolog.TailSize - pContext->nBytesToReceive,
  363. pContext->nBytesToReceive,
  364. 0);
  365. else
  366. result = 0;
  367. if (result != SOCKET_ERROR)
  368. {
  369. pContext->nBytesToReceive -= result;
  370. if (!pContext->nBytesToReceive)
  371. {
  372. // Cool, we have the whole message
  373. pContext->bRecvDone = TRUE;
  374. pContext->bPrologReceived = FALSE;
  375. pContext->bHeadReceived = FALSE;
  376. pContext->nBytesToReceive = sizeof(pContext->Prolog);
  377. result = 1; // Hack, otherwise the loop can exit
  378. }
  379. }
  380. }
  381. } while (result != 0 && !pContext->bRecvDone &&
  382. result != SOCKET_ERROR);
  383. // At this point the message is not 100%
  384. // received
  385. // Only pContext->bRecvDone indicates this
  386. // return FALSE if error is occured
  387. if (!result)
  388. return FALSE; // connection was gracefully closed
  389. if (result == SOCKET_ERROR)
  390. {
  391. if (WSAGetLastError() == WSAEWOULDBLOCK)
  392. return TRUE; // the call will block, but ok
  393. else
  394. return FALSE; // other SOCKET_ERROR
  395. }
  396. return TRUE; // it is ok
  397. }
  398. VOID
  399. _RClx_Bitmap(PRCLXCONTEXT pContext)
  400. {
  401. WCHAR wszFeed[MAX_STRING_LENGTH];
  402. PBMPFEEDBACK pBmpFeed;
  403. PRCLXBITMAPFEED pRClxFeed = pContext->pHead;
  404. // If BitmapInfo is empty (glyph) it's not sent
  405. // Hence the HeadSize is smaller
  406. if (pContext->Prolog.HeadSize > sizeof(*pRClxFeed))
  407. {
  408. TRACE((WARNING_MESSAGE,
  409. "BitmapOut: Received header is larger than expected\n"));
  410. ASSERT(0);
  411. goto exitpt;
  412. }
  413. if (pContext->Prolog.TailSize != pRClxFeed->bmpsize)
  414. {
  415. TRACE((WARNING_MESSAGE,
  416. "BitmapOut: Received bits are not equal to expected."
  417. "Expect:%d, read:%d\n",
  418. pRClxFeed->bmpsize, pContext->Prolog.TailSize));
  419. ASSERT(0);
  420. goto exitpt;
  421. }
  422. pBmpFeed = _alloca(sizeof(*pBmpFeed) + pRClxFeed->bmisize + pRClxFeed->bmpsize);
  423. if (!pBmpFeed)
  424. {
  425. TRACE((WARNING_MESSAGE,
  426. "BitmapOut:alloca failed to allocate 0x%x bytes\n",
  427. sizeof(*pBmpFeed) + pRClxFeed->bmpsize));
  428. goto exitpt;
  429. }
  430. pBmpFeed->lProcessId = pContext->hSocket;
  431. pBmpFeed->bmpsize = pRClxFeed->bmpsize;
  432. pBmpFeed->bmiSize = pRClxFeed->bmisize;
  433. pBmpFeed->xSize = pRClxFeed->xSize;
  434. pBmpFeed->ySize = pRClxFeed->ySize;
  435. // Check and copy bitmapinfo
  436. if (pBmpFeed->bmiSize > sizeof(pBmpFeed->BitmapInfo))
  437. {
  438. TRACE((WARNING_MESSAGE,
  439. "BitmapOut:BITMAPINFO is more than expected. Rejecting\n"));
  440. goto exitpt;
  441. }
  442. memcpy(&(pBmpFeed->BitmapInfo),
  443. &(pRClxFeed->BitmapInfo),
  444. pBmpFeed->bmiSize);
  445. // Copy the bits after the structure
  446. memcpy(((BYTE *)(&pBmpFeed->BitmapInfo)) + pBmpFeed->bmiSize,
  447. pContext->pTail,
  448. pContext->Prolog.TailSize);
  449. // Convert the glyph
  450. if (!Glyph2String(pBmpFeed, wszFeed, sizeof(wszFeed)/sizeof(WCHAR)))
  451. {
  452. goto exitpt;
  453. }
  454. _CheckForWaitingWorker(wszFeed, (DWORD)(pContext->hSocket));
  455. exitpt:
  456. ;
  457. }
  458. /*++
  459. * Function:
  460. * RClx_MsgReceived
  461. * Description:
  462. * Dispatches a received message. Converts it in proper internal
  463. * format and passes it to some queues.c function to find a waiting
  464. * worker
  465. * The message is in the RCLX context.
  466. * Arguments:
  467. * pContext - RCLX context
  468. * Called by:
  469. * RClx_DispatchWSockEvent upon FD_READ event
  470. --*/
  471. VOID RClx_MsgReceived(PRCLXCONTEXT pContext)
  472. {
  473. UINT32 *puSessionID;
  474. ASSERT(pContext);
  475. ASSERT(pContext->pOwner);
  476. switch(pContext->Prolog.FeedType)
  477. {
  478. case FEED_CONNECT:
  479. _CheckForWorkerWaitingConnect((HWND)pContext, pContext->hSocket);
  480. break;
  481. case FEED_LOGON:
  482. puSessionID = (UINT *)pContext->pHead;
  483. ASSERT(puSessionID);
  484. _SetSessionID(pContext->hSocket, *puSessionID);
  485. break;
  486. case FEED_DISCONNECT:
  487. _SetClientDead(pContext->hSocket);
  488. _CheckForWorkerWaitingDisconnect(pContext->hSocket);
  489. _CancelWaitingWorker(pContext->hSocket);
  490. break;
  491. case FEED_BITMAP:
  492. _RClx_Bitmap(pContext);
  493. break;
  494. case FEED_TEXTOUT:
  495. //TRACE((WARNING_MESSAGE, "TEXTOUT order is not implemented\n"));
  496. // pContext->pHead - unused
  497. _CheckForWaitingWorker(
  498. (LPCWSTR)(pContext->pTail),
  499. (DWORD)(pContext->hSocket));
  500. break;
  501. case FEED_TEXTOUTA:
  502. TRACE((WARNING_MESSAGE, "TEXTOUTA order not implemented\n"));
  503. break;
  504. case FEED_CLIPBOARD:
  505. {
  506. PRCLXCLIPBOARDFEED pRClxClipFeed = pContext->pHead;
  507. _CheckForWorkerWaitingClipboard(
  508. pContext->pOwner,
  509. pRClxClipFeed->uiFormat,
  510. pRClxClipFeed->nClipBoardSize,
  511. pContext->pTail,
  512. (DWORD)(pContext->hSocket));
  513. }
  514. break;
  515. case FEED_CLIENTINFO:
  516. ASSERT(0); // Shouldn't appear here
  517. break;
  518. case FEED_WILLCALLAGAIN:
  519. TRACE((INFO_MESSAGE, "WILLCALLAGAIN received, disconnecting the client\n"));
  520. ASSERT(pContext->pOwner);
  521. EnterCriticalSection(g_lpcsGuardWaitQueue);
  522. pContext->pOwner->bWillCallAgain = TRUE;
  523. pContext->pOwner->dead = TRUE;
  524. _CancelWaitingWorker(pContext->hSocket);
  525. pContext->pOwner->hClient = NULL;
  526. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  527. _RClx_RemoveContextFromGlobalQueue(pContext);
  528. RClx_EndRecv(pContext);
  529. break;
  530. case FEED_DATA:
  531. {
  532. PCONNECTINFO pCI;
  533. PRCLXDATA pRClxData;
  534. PRCLXDATACHAIN pNewEntry;
  535. PWAIT4STRING pWait;
  536. TRACE((ALIVE_MESSAGE, "RClx data arrived\n"));
  537. pCI = pContext->pOwner;
  538. ASSERT(pCI);
  539. pRClxData = (PRCLXDATA)pContext->pHead;
  540. ASSERT(pRClxData);
  541. ASSERT(pRClxData->uiSize + sizeof(*pRClxData) ==
  542. (pContext->Prolog.HeadSize));
  543. pWait = _RetrieveFromWaitQByOwner(pCI);
  544. pNewEntry = malloc(sizeof(*pNewEntry) + pRClxData->uiSize);
  545. if (!pNewEntry)
  546. {
  547. // trash out the received data
  548. TRACE((WARNING_MESSAGE,
  549. "Can't allocate %d bytes for RCLXDATACHAIN\n",
  550. pContext->Prolog.HeadSize));
  551. break;
  552. }
  553. pNewEntry->uiOffset = 0;
  554. pNewEntry->pNext = NULL;
  555. memcpy(&pNewEntry->RClxData,
  556. pRClxData,
  557. pContext->Prolog.HeadSize);
  558. EnterCriticalSection(g_lpcsGuardWaitQueue);
  559. if (!pCI->pRClxDataChain)
  560. pCI->pRClxDataChain = pCI->pRClxLastDataChain = pNewEntry;
  561. else
  562. {
  563. ASSERT(pCI->pRClxLastDataChain);
  564. pCI->pRClxLastDataChain->pNext = pNewEntry;
  565. pCI->pRClxLastDataChain = pNewEntry;
  566. }
  567. // signal the worker
  568. if (pWait &&
  569. pWait->WaitType == WAIT_DATA)
  570. SetEvent(pWait->evWait);
  571. else
  572. TRACE((WARNING_MESSAGE, "no event to signal\n"));
  573. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  574. break;
  575. }
  576. default:
  577. ASSERT(0);
  578. }
  579. }
  580. /*++
  581. * Function:
  582. * RClx_SendBuffer
  583. * Description:
  584. * Sends a buffer thru socket. The socket must be BLOCKING
  585. * so, all the buffer is send after this function exits
  586. * Arguments:
  587. * hSocket - the socket
  588. * pBuffer - the buffer
  589. * nSize - buffer size
  590. * Return value:
  591. * TRUE on success, FALSE if the connection failed
  592. * Called by:
  593. * RClx_SendMessage, RClx_SendConnectInfo
  594. --*/
  595. BOOL RClx_SendBuffer(SOCKET hSocket, PVOID pBuffer, UINT nSize)
  596. {
  597. INT result = 0;
  598. UINT nBytesToSend = nSize;
  599. ASSERT(hSocket != INVALID_SOCKET);
  600. ASSERT(pBuffer);
  601. if (!nSize)
  602. goto exitpt;
  603. do {
  604. result = send(hSocket, pBuffer, nBytesToSend, 0);
  605. if (result != SOCKET_ERROR)
  606. {
  607. nBytesToSend -= result;
  608. (BYTE *)pBuffer += result;
  609. } else
  610. if (WSAGetLastError() == WSAEWOULDBLOCK)
  611. {
  612. // The socket is blocked, wait on select until it's writable
  613. FD_SET fd;
  614. FD_ZERO(&fd);
  615. FD_SET(hSocket, &fd);
  616. result = select(-1, NULL, &fd, NULL, NULL);
  617. }
  618. } while (result != SOCKET_ERROR && nBytesToSend);
  619. exitpt:
  620. return (result != SOCKET_ERROR);
  621. }
  622. /*++
  623. * Function:
  624. * RClx_SendMessage
  625. * Description:
  626. * Sends an window message to the client
  627. * Arguments:
  628. * pContext - RCLX context
  629. * uiMessage - message Id
  630. * wParam - word parameter
  631. * lParam - long parameter
  632. * Return value:
  633. * TRUE on success
  634. * Called by:
  635. * scfuncs.c:SCSenddata
  636. --*/
  637. BOOL RClx_SendMessage(PRCLXCONTEXT pContext,
  638. UINT uiMessage,
  639. WPARAM wParam,
  640. LPARAM lParam)
  641. {
  642. RCLXMSG ClxMsg;
  643. RCLXREQPROLOG ReqProlog;
  644. SOCKET hSocket;
  645. BOOL rv = TRUE;
  646. ASSERT(pContext);
  647. hSocket = pContext->hSocket;
  648. ASSERT(hSocket != INVALID_SOCKET);
  649. ReqProlog.ReqType = REQ_MESSAGE;
  650. ReqProlog.ReqSize = sizeof(ClxMsg);
  651. ClxMsg.message = uiMessage;
  652. ClxMsg.wParam = (UINT32)wParam;
  653. ClxMsg.lParam = (UINT32)lParam;
  654. // Send the request prolog
  655. rv = RClx_SendBuffer(pContext->hSocket, &ReqProlog, sizeof(ReqProlog));
  656. if (!rv)
  657. {
  658. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  659. goto exitpt;
  660. }
  661. // Try to send the whole message
  662. rv = RClx_SendBuffer(pContext->hSocket, &ClxMsg, sizeof(ClxMsg));
  663. if (!rv)
  664. {
  665. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  666. goto exitpt;
  667. }
  668. if (strstr(pContext->pOwner->szClientType, "WIN16") != NULL)
  669. Sleep(100); // Don't send very fast to WIN16
  670. exitpt:
  671. return rv;
  672. }
  673. /*++
  674. * Function:
  675. * RClx_SendConnectInfo
  676. * Description:
  677. * Sends the information to the client about Hydra server to connect to
  678. * like, server name, resolution etc
  679. * Arguments:
  680. * pContext - RCLX context
  681. * xRes, yRes - resolution
  682. * ConnectionFlags -
  683. * - the "client/hydra server" connection
  684. * will be compressed
  685. * -
  686. * the bitmaps received by the client will be saved
  687. * on the disc
  688. * Return value:
  689. * TRUE on success
  690. * Called by:
  691. * scfuncs.c:SCConnect
  692. --*/
  693. BOOL RClx_SendConnectInfo(PRCLXCONTEXT pContext,
  694. LPCWSTR wszHydraServer,
  695. INT xRes,
  696. INT yRes,
  697. INT ConnectionFlags)
  698. {
  699. RCLXREQPROLOG ReqProlog;
  700. SOCKET hSocket;
  701. RCLXCONNECTINFO ClxInfo;
  702. BOOL rv;
  703. ASSERT(pContext);
  704. ASSERT(pContext->pOwner);
  705. hSocket = pContext->hSocket;
  706. ASSERT(hSocket != INVALID_SOCKET);
  707. ReqProlog.ReqType = REQ_CONNECTINFO;
  708. ReqProlog.ReqSize = sizeof(ClxInfo);
  709. ClxInfo.YourID = pContext->pOwner->dwThreadId;
  710. ClxInfo.xResolution = xRes;
  711. ClxInfo.yResolution = yRes;
  712. ClxInfo.bLowSpeed = (ConnectionFlags & TSFLAG_COMPRESSION)?TRUE:FALSE;
  713. ClxInfo.bPersistentCache = (ConnectionFlags & TSFLAG_BITMAPCACHE)?TRUE:FALSE;
  714. WideCharToMultiByte(
  715. CP_ACP,
  716. 0,
  717. wszHydraServer,
  718. -1,
  719. ClxInfo.szHydraServer,
  720. sizeof(ClxInfo.szHydraServer),
  721. NULL, NULL);
  722. // Send the request prolog
  723. rv = RClx_SendBuffer(pContext->hSocket, &ReqProlog, sizeof(ReqProlog));
  724. if (!rv)
  725. {
  726. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  727. goto exitpt;
  728. }
  729. // Try to send the whole message
  730. rv = RClx_SendBuffer(pContext->hSocket, &ClxInfo, sizeof(ClxInfo));
  731. if (!rv)
  732. {
  733. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  734. goto exitpt;
  735. }
  736. exitpt:
  737. return rv;
  738. }
  739. /*++
  740. * Function:
  741. * RClx_SendClipboard
  742. * Description:
  743. * Sends a new clipboard content for the client machine
  744. * Arguments:
  745. * pContext - RCLX context
  746. * pClipboard - clipboard content
  747. * nDataLength - data length
  748. * uiFormat - the clipboard format
  749. * Return value:
  750. * TRUE on success
  751. * Called by:
  752. * scfuncs.c:SCClipboard
  753. --*/
  754. BOOL RClx_SendClipboard(
  755. PRCLXCONTEXT pContext,
  756. PVOID pClipboard,
  757. UINT nDataLength,
  758. UINT uiFormat)
  759. {
  760. RCLXREQPROLOG ReqProlog;
  761. SOCKET hSocket;
  762. RCLXCLIPBOARD SetClipReq;
  763. BOOL rv = FALSE;
  764. ASSERT(pContext);
  765. ASSERT((pClipboard && nDataLength) || (!pClipboard && !nDataLength));
  766. hSocket = pContext->hSocket;
  767. ASSERT(hSocket != INVALID_SOCKET);
  768. ReqProlog.ReqType = REQ_SETCLIPBOARD;
  769. ReqProlog.ReqSize = sizeof(SetClipReq) + nDataLength;
  770. SetClipReq.uiFormat = uiFormat;
  771. // Send the request prolog
  772. rv = RClx_SendBuffer(pContext->hSocket, &ReqProlog, sizeof(ReqProlog));
  773. if (!rv)
  774. {
  775. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  776. goto exitpt;
  777. }
  778. rv = RClx_SendBuffer(pContext->hSocket, &SetClipReq, sizeof(SetClipReq));
  779. if (!rv)
  780. {
  781. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  782. goto exitpt;
  783. }
  784. // Send the data after all (if any)
  785. if (pClipboard)
  786. {
  787. rv = RClx_SendBuffer(pContext->hSocket, pClipboard, nDataLength);
  788. if (!rv)
  789. {
  790. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  791. goto exitpt;
  792. }
  793. }
  794. exitpt:
  795. return rv;
  796. }
  797. /*++
  798. * Function:
  799. * RClx_SendClipboardRequest
  800. * Description:
  801. * Request the clipboard content from the client machine
  802. * Arguments:
  803. * pContext - RCLX context
  804. * uiFormat - the desired clipboard format
  805. * Return value:
  806. * TRUE on success
  807. * Called by:
  808. * scfuncs.c:SCClipboard
  809. --*/
  810. BOOL RClx_SendClipboardRequest(
  811. PRCLXCONTEXT pContext,
  812. UINT uiFormat)
  813. {
  814. RCLXREQPROLOG ReqProlog;
  815. SOCKET hSocket;
  816. RCLXCLIPBOARD GetClipReq;
  817. BOOL rv = FALSE;
  818. ASSERT(pContext);
  819. ASSERT(pContext->pOwner);
  820. hSocket = pContext->hSocket;
  821. ASSERT(hSocket != INVALID_SOCKET);
  822. pContext->pOwner->bRClxClipboardReceived = FALSE;
  823. ReqProlog.ReqType = REQ_GETCLIPBOARD;
  824. ReqProlog.ReqSize = sizeof(GetClipReq);
  825. GetClipReq.uiFormat = uiFormat;
  826. // Send the request prolog
  827. rv = RClx_SendBuffer(pContext->hSocket, &ReqProlog, sizeof(ReqProlog));
  828. if (!rv)
  829. {
  830. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  831. goto exitpt;
  832. }
  833. rv = RClx_SendBuffer(pContext->hSocket, &GetClipReq, sizeof(GetClipReq));
  834. if (!rv)
  835. {
  836. TRACE((ERROR_MESSAGE, "Can't send: %d\n", WSAGetLastError()));
  837. goto exitpt;
  838. }
  839. exitpt:
  840. return rv;
  841. }
  842. /*++
  843. * Function:
  844. * RClx_CloseSocket
  845. * Description:
  846. * Gracefully closes a socket
  847. * Arguments:
  848. * hSocket - socket for closing
  849. * Called by:
  850. * RClx_EndRecv
  851. * RClx_DispatchWSockEvent
  852. * RClx_Listen
  853. --*/
  854. VOID RClx_CloseSocket(SOCKET hSocket)
  855. {
  856. BYTE tBuf[128];
  857. INT recvresult;
  858. ASSERT(hSocket != INVALID_SOCKET);
  859. WSAAsyncSelect(hSocket, g_hWindow, 0, 0);
  860. shutdown(hSocket, SD_SEND);
  861. do {
  862. recvresult = recv(hSocket, tBuf, sizeof(tBuf), 0);
  863. } while (recvresult && recvresult != SOCKET_ERROR);
  864. closesocket(hSocket);
  865. }
  866. //
  867. // search & destroy from g_pRClxList
  868. //
  869. VOID _RClx_RemoveContextFromGlobalQueue(PRCLXCONTEXT pContext)
  870. {
  871. PRCLXCONTEXT pRClxIter = g_pRClxList;
  872. PRCLXCONTEXT pRClxPrev = NULL;
  873. while (pRClxIter && pRClxIter != pContext)
  874. {
  875. pRClxPrev = pRClxIter;
  876. pRClxIter = pRClxIter->pNext;
  877. }
  878. if (!pRClxIter)
  879. goto exitpt;
  880. if (!pRClxPrev)
  881. g_pRClxList = pContext->pNext;
  882. else
  883. pRClxPrev->pNext = pContext->pNext;
  884. exitpt:
  885. ;
  886. }
  887. /*+++
  888. * Function:
  889. * _AddRClxContextToClientConnection
  890. * Description:
  891. * FEED_CLIENTINFO is received, now find a proper thread to assign the
  892. * RCLX context
  893. * Argument:
  894. * pRClxCtx - RCLX context
  895. * Called by:
  896. * RClx_DispatchWSockEvent
  897. *
  898. --*/
  899. VOID
  900. _AddRClxContextToClientConnection(PRCLXCONTEXT pRClxCtx)
  901. {
  902. PRCLXCLIENTINFOFEED pClntInfo;
  903. PCONNECTINFO pCI;
  904. ASSERT(pRClxCtx);
  905. ASSERT(pRClxCtx->Prolog.FeedType == FEED_CLIENTINFO);
  906. EnterCriticalSection(g_lpcsGuardWaitQueue);
  907. pClntInfo = (PRCLXCLIENTINFOFEED)(pRClxCtx->pHead);
  908. ASSERT(pClntInfo);
  909. TRACE((ALIVE_MESSAGE,
  910. "CLIENTINFO received, recon=%d info: %s\n",
  911. pClntInfo->nReconnectAct,
  912. pClntInfo->szClientInfo));
  913. // If nReconnectAct is non zero then lookup for thread which waits
  914. // reconnection
  915. if (pClntInfo->nReconnectAct)
  916. {
  917. ASSERT(pClntInfo->ReconnectID);
  918. // Identify by dwProcessId
  919. pCI = _CheckForWorkerWaitingReconnectAndSetNewId(
  920. (HWND)pRClxCtx,
  921. (DWORD)pClntInfo->ReconnectID,
  922. (DWORD)pRClxCtx->hSocket);
  923. if (!pCI)
  924. {
  925. TRACE((WARNING_MESSAGE,
  926. "Nobody is waiting for REconnect."
  927. " Disconnecting the socket\n"));
  928. _RClx_RemoveContextFromGlobalQueue(pRClxCtx);
  929. RClx_EndRecv(pRClxCtx);
  930. } else {
  931. _snprintf(pCI->szClientType, sizeof(pCI->szClientType),
  932. "%s",
  933. pClntInfo->szClientInfo);
  934. pRClxCtx->pOwner = pCI;
  935. }
  936. goto exitpt;
  937. }
  938. // Get the first waiting for connect from remote clx
  939. // accepted socket goes into dwProcessId
  940. // pRClxCtx goes int hClient member of CONNECTINFO
  941. // structure. In order to determine the different IDs
  942. // (one is process Id, and second one is socket)
  943. // a member bRClxMode is used
  944. pCI = _CheckForWorkerWaitingConnectAndSetId((HWND)pRClxCtx,
  945. (DWORD)pRClxCtx->hSocket);
  946. if (!pCI)
  947. {
  948. TRACE((WARNING_MESSAGE,
  949. "Nobody is waiting for connect."
  950. " Disconnecting the socket\n"));
  951. _RClx_RemoveContextFromGlobalQueue(pRClxCtx);
  952. RClx_EndRecv(pRClxCtx);
  953. goto exitpt;
  954. } else {
  955. _snprintf(pCI->szClientType, sizeof(pCI->szClientType),
  956. "%s",
  957. pClntInfo->szClientInfo);
  958. pRClxCtx->pOwner = pCI;
  959. }
  960. exitpt:
  961. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  962. }
  963. /*++
  964. * Function:
  965. * RClx_DispatchWSockEvent
  966. * Description:
  967. * Dispatches winsock events: FD_ACCEPT, FD_READ and FD_CLOSE
  968. * The event is passed by the feedback window/thread
  969. * Arguments:
  970. * hSocket - the socket for which the event is
  971. * lEvent - actualy lParam of the winsock message
  972. * contains the event and error (if any)
  973. * Called by:
  974. * tclient.c:_FeedbackWndProc
  975. --*/
  976. VOID RClx_DispatchWSockEvent(SOCKET hSocket, LPARAM lEvent)
  977. {
  978. SOCKET hClient;
  979. PCONNECTINFO pCI;
  980. PRCLXCONTEXT pRClxCtx;
  981. if (WSAGETSELECTERROR(lEvent))
  982. {
  983. TRACE((ERROR_MESSAGE,
  984. "Select error: %d\n",
  985. WSAGETSELECTERROR(lEvent)));
  986. goto perform_close; // On error
  987. // behave like the socket is closed
  988. }
  989. switch(WSAGETSELECTEVENT(lEvent))
  990. {
  991. case FD_ACCEPT:
  992. // Accept all incoming sockets
  993. // look in our WaitQ for a free worker waiting connection
  994. // if there's no free worker disconnect the socket
  995. // so the remote side knows that connection is unwanted
  996. ASSERT(hSocket == g_hSrvSocket);
  997. // Accept all incoming connections
  998. while ((hClient = RClx_Accept()) != INVALID_SOCKET)
  999. {
  1000. // Put this socket in Async receive mode
  1001. // The first operation is send, so we well not lose
  1002. // FD_READ message
  1003. if (WSAAsyncSelect(hClient,
  1004. g_hWindow,
  1005. WM_WSOCK,
  1006. FD_READ|FD_CLOSE) == SOCKET_ERROR)
  1007. {
  1008. TRACE((ERROR_MESSAGE,
  1009. "Can't \"select\" client socket: %d."
  1010. "Disconnecting the socket\n",
  1011. WSAGetLastError()));
  1012. RClx_CloseSocket(hClient);
  1013. goto exitpt;
  1014. }
  1015. // Allocate our context
  1016. pRClxCtx = RClx_StartRecv();
  1017. if (!pRClxCtx)
  1018. {
  1019. TRACE((WARNING_MESSAGE,
  1020. "Can't allocate memmory. Disconnecting the socket\n"));
  1021. RClx_CloseSocket(hClient);
  1022. goto exitpt;
  1023. }
  1024. pRClxCtx->hSocket = hClient;
  1025. pRClxCtx->nBytesToReceive = sizeof(pRClxCtx->Prolog);
  1026. // Add this context to the list of connections which didn't
  1027. // receive their FEED_CLIENTINFO yet
  1028. // we don't need crit sect, 'cause this is single thread op
  1029. pRClxCtx->pNext = g_pRClxList;
  1030. g_pRClxList = pRClxCtx;
  1031. PostMessage(g_hWindow, WM_WSOCK, hClient, FD_READ);
  1032. }
  1033. break;
  1034. case FD_READ:
  1035. // Check first if this comes from RClxList socket
  1036. pRClxCtx = g_pRClxList;
  1037. while (pRClxCtx && pRClxCtx->hSocket != hSocket)
  1038. pRClxCtx = pRClxCtx->pNext;
  1039. if (pRClxCtx)
  1040. {
  1041. RClx_Receive(pRClxCtx);
  1042. if (pRClxCtx->bRecvDone)
  1043. {
  1044. pRClxCtx->bRecvDone = FALSE;
  1045. if (pRClxCtx->Prolog.FeedType == FEED_CLIENTINFO)
  1046. {
  1047. _RClx_RemoveContextFromGlobalQueue(pRClxCtx);
  1048. pRClxCtx->pNext = NULL;
  1049. //
  1050. // Don't use pRClxCtx past this point
  1051. // this function could call RClx_EndRecv
  1052. //
  1053. _AddRClxContextToClientConnection(pRClxCtx);
  1054. }
  1055. break;
  1056. }
  1057. }
  1058. // What if the connection is closed here ?!
  1059. // Solution: use the same critical section as the queue manager
  1060. EnterCriticalSection(g_lpcsGuardWaitQueue);
  1061. pCI = _CheckIsAcceptable((DWORD)hSocket, TRUE);
  1062. if (pCI && pCI->hClient)
  1063. {
  1064. pRClxCtx = (PRCLXCONTEXT)pCI->hClient;
  1065. RClx_Receive(pRClxCtx);
  1066. if (pRClxCtx->bRecvDone)
  1067. {
  1068. pRClxCtx->bRecvDone = FALSE;
  1069. RClx_MsgReceived(pRClxCtx);
  1070. }
  1071. }
  1072. LeaveCriticalSection(g_lpcsGuardWaitQueue);
  1073. break;
  1074. case FD_CLOSE:
  1075. perform_close:
  1076. // The socket closes, "last call" for the worker
  1077. pCI = _CheckIsAcceptable((DWORD)hSocket, TRUE);
  1078. if (pCI)
  1079. {
  1080. _SetClientDead((DWORD)hSocket);
  1081. _CheckForWorkerWaitingDisconnect((DWORD)hSocket);
  1082. _CancelWaitingWorker((DWORD)hSocket);
  1083. }
  1084. break;
  1085. default:
  1086. ASSERT(0);
  1087. }
  1088. exitpt:
  1089. ;
  1090. }