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.

VNCSConnectionST.cxx 32KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2009-2019 Pierre Ossman for Cendio AB
  3. * Copyright 2018 Peter Astrand for Cendio AB
  4. *
  5. * This is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This software is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this software; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  18. * USA.
  19. */
  20. #include <network/TcpSocket.h>
  21. #include <rfb/ComparingUpdateTracker.h>
  22. #include <rfb/Encoder.h>
  23. #include <rfb/KeyRemapper.h>
  24. #include <rfb/LogWriter.h>
  25. #include <rfb/Security.h>
  26. #include <rfb/ServerCore.h>
  27. #include <rfb/SMsgWriter.h>
  28. #include <rfb/VNCServerST.h>
  29. #include <rfb/VNCSConnectionST.h>
  30. #include <rfb/screenTypes.h>
  31. #include <rfb/fenceTypes.h>
  32. #include <rfb/ledStates.h>
  33. #define XK_LATIN1
  34. #define XK_MISCELLANY
  35. #define XK_XKB_KEYS
  36. #include <rfb/keysymdef.h>
  37. using namespace rfb;
  38. static LogWriter vlog("VNCSConnST");
  39. static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
  40. VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
  41. bool reverse)
  42. : sock(s), reverseConnection(reverse),
  43. inProcessMessages(false),
  44. pendingSyncFence(false), syncFence(false), fenceFlags(0),
  45. fenceDataLen(0), fenceData(NULL), congestionTimer(this),
  46. losslessTimer(this), server(server_),
  47. updateRenderedCursor(false), removeRenderedCursor(false),
  48. continuousUpdates(false), encodeManager(this), idleTimer(this),
  49. pointerEventTime(0), clientHasCursor(false)
  50. {
  51. setStreams(&sock->inStream(), &sock->outStream());
  52. peerEndpoint.buf = sock->getPeerEndpoint();
  53. // Kick off the idle timer
  54. if (rfb::Server::idleTimeout) {
  55. // minimum of 15 seconds while authenticating
  56. if (rfb::Server::idleTimeout < 15)
  57. idleTimer.start(secsToMillis(15));
  58. else
  59. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  60. }
  61. }
  62. VNCSConnectionST::~VNCSConnectionST()
  63. {
  64. // If we reach here then VNCServerST is deleting us!
  65. if (closeReason.buf)
  66. vlog.info("closing %s: %s", peerEndpoint.buf, closeReason.buf);
  67. // Release any keys the client still had pressed
  68. while (!pressedKeys.empty()) {
  69. rdr::U32 keysym, keycode;
  70. keysym = pressedKeys.begin()->second;
  71. keycode = pressedKeys.begin()->first;
  72. pressedKeys.erase(pressedKeys.begin());
  73. vlog.debug("Releasing key 0x%x / 0x%x on client disconnect",
  74. keysym, keycode);
  75. server->keyEvent(keysym, keycode, false);
  76. }
  77. delete [] fenceData;
  78. }
  79. // SConnection methods
  80. bool VNCSConnectionST::accessCheck(AccessRights ar) const
  81. {
  82. // Reverse connections are user initiated, so they are implicitly
  83. // allowed to bypass the query
  84. if (reverseConnection)
  85. ar &= ~AccessNoQuery;
  86. return SConnection::accessCheck(ar);
  87. }
  88. void VNCSConnectionST::close(const char* reason)
  89. {
  90. SConnection::close(reason);
  91. // Log the reason for the close
  92. if (!closeReason.buf)
  93. closeReason.buf = strDup(reason);
  94. else
  95. vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
  96. try {
  97. if (sock->outStream().hasBufferedData()) {
  98. sock->outStream().cork(false);
  99. sock->outStream().flush();
  100. if (sock->outStream().hasBufferedData())
  101. vlog.error("Failed to flush remaining socket data on close");
  102. }
  103. } catch (rdr::Exception& e) {
  104. vlog.error("Failed to flush remaining socket data on close: %s", e.str());
  105. }
  106. // Just shutdown the socket and mark our state as closing. Eventually the
  107. // calling code will call VNCServerST's removeSocket() method causing us to
  108. // be deleted.
  109. sock->shutdown();
  110. }
  111. // Methods called from VNCServerST
  112. bool VNCSConnectionST::init()
  113. {
  114. try {
  115. initialiseProtocol();
  116. } catch (rdr::Exception& e) {
  117. close(e.str());
  118. return false;
  119. }
  120. return true;
  121. }
  122. void VNCSConnectionST::processMessages()
  123. {
  124. if (state() == RFBSTATE_CLOSING) return;
  125. try {
  126. inProcessMessages = true;
  127. // Get the underlying transport to build large packets if we send
  128. // multiple small responses.
  129. getOutStream()->cork(true);
  130. while (true) {
  131. if (pendingSyncFence)
  132. syncFence = true;
  133. if (!processMsg())
  134. break;
  135. if (syncFence) {
  136. writer()->writeFence(fenceFlags, fenceDataLen, fenceData);
  137. syncFence = false;
  138. pendingSyncFence = false;
  139. }
  140. }
  141. // Flush out everything in case we go idle after this.
  142. getOutStream()->cork(false);
  143. inProcessMessages = false;
  144. // If there were anything requiring an update, try to send it here.
  145. // We wait until now with this to aggregate responses and to give
  146. // higher priority to user actions such as keyboard and pointer events.
  147. writeFramebufferUpdate();
  148. } catch (rdr::EndOfStream&) {
  149. close("Clean disconnection");
  150. } catch (rdr::Exception &e) {
  151. close(e.str());
  152. }
  153. }
  154. void VNCSConnectionST::flushSocket()
  155. {
  156. if (state() == RFBSTATE_CLOSING) return;
  157. try {
  158. sock->outStream().flush();
  159. // Flushing the socket might release an update that was previously
  160. // delayed because of congestion.
  161. if (!sock->outStream().hasBufferedData())
  162. writeFramebufferUpdate();
  163. } catch (rdr::Exception &e) {
  164. close(e.str());
  165. }
  166. }
  167. void VNCSConnectionST::pixelBufferChange()
  168. {
  169. try {
  170. if (!authenticated()) return;
  171. if (client.width() && client.height() &&
  172. (server->getPixelBuffer()->width() != client.width() ||
  173. server->getPixelBuffer()->height() != client.height()))
  174. {
  175. // We need to clip the next update to the new size, but also add any
  176. // extra bits if it's bigger. If we wanted to do this exactly, something
  177. // like the code below would do it, but at the moment we just update the
  178. // entire new size. However, we do need to clip the damagedCursorRegion
  179. // because that might be added to updates in writeFramebufferUpdate().
  180. //updates.intersect(server->pb->getRect());
  181. //
  182. //if (server->pb->width() > client.width())
  183. // updates.add_changed(Rect(client.width(), 0, server->pb->width(),
  184. // server->pb->height()));
  185. //if (server->pb->height() > client.height())
  186. // updates.add_changed(Rect(0, client.height(), client.width(),
  187. // server->pb->height()));
  188. damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());
  189. client.setDimensions(server->getPixelBuffer()->width(),
  190. server->getPixelBuffer()->height(),
  191. server->getScreenLayout());
  192. if (state() == RFBSTATE_NORMAL) {
  193. if (!client.supportsDesktopSize()) {
  194. close("Client does not support desktop resize");
  195. return;
  196. }
  197. writer()->writeDesktopSize(reasonServer);
  198. }
  199. // Drop any lossy tracking that is now outside the framebuffer
  200. encodeManager.pruneLosslessRefresh(Region(server->getPixelBuffer()->getRect()));
  201. }
  202. // Just update the whole screen at the moment because we're too lazy to
  203. // work out what's actually changed.
  204. updates.clear();
  205. updates.add_changed(server->getPixelBuffer()->getRect());
  206. writeFramebufferUpdate();
  207. } catch(rdr::Exception &e) {
  208. close(e.str());
  209. }
  210. }
  211. void VNCSConnectionST::writeFramebufferUpdateOrClose()
  212. {
  213. try {
  214. writeFramebufferUpdate();
  215. } catch(rdr::Exception &e) {
  216. close(e.str());
  217. }
  218. }
  219. void VNCSConnectionST::screenLayoutChangeOrClose(rdr::U16 reason)
  220. {
  221. try {
  222. screenLayoutChange(reason);
  223. writeFramebufferUpdate();
  224. } catch(rdr::Exception &e) {
  225. close(e.str());
  226. }
  227. }
  228. void VNCSConnectionST::bellOrClose()
  229. {
  230. try {
  231. if (state() == RFBSTATE_NORMAL) writer()->writeBell();
  232. } catch(rdr::Exception& e) {
  233. close(e.str());
  234. }
  235. }
  236. void VNCSConnectionST::setDesktopNameOrClose(const char *name)
  237. {
  238. try {
  239. setDesktopName(name);
  240. writeFramebufferUpdate();
  241. } catch(rdr::Exception& e) {
  242. close(e.str());
  243. }
  244. }
  245. void VNCSConnectionST::setCursorOrClose()
  246. {
  247. try {
  248. setCursor();
  249. writeFramebufferUpdate();
  250. } catch(rdr::Exception& e) {
  251. close(e.str());
  252. }
  253. }
  254. void VNCSConnectionST::setLEDStateOrClose(unsigned int state)
  255. {
  256. try {
  257. setLEDState(state);
  258. writeFramebufferUpdate();
  259. } catch(rdr::Exception& e) {
  260. close(e.str());
  261. }
  262. }
  263. void VNCSConnectionST::requestClipboardOrClose()
  264. {
  265. try {
  266. if (!accessCheck(AccessCutText)) return;
  267. if (!rfb::Server::acceptCutText) return;
  268. if (state() != RFBSTATE_NORMAL) return;
  269. requestClipboard();
  270. } catch(rdr::Exception& e) {
  271. close(e.str());
  272. }
  273. }
  274. void VNCSConnectionST::announceClipboardOrClose(bool available)
  275. {
  276. try {
  277. if (!accessCheck(AccessCutText)) return;
  278. if (!rfb::Server::sendCutText) return;
  279. if (state() != RFBSTATE_NORMAL) return;
  280. announceClipboard(available);
  281. } catch(rdr::Exception& e) {
  282. close(e.str());
  283. }
  284. }
  285. void VNCSConnectionST::sendClipboardDataOrClose(const char* data)
  286. {
  287. try {
  288. if (!accessCheck(AccessCutText)) return;
  289. if (!rfb::Server::sendCutText) return;
  290. if (state() != RFBSTATE_NORMAL) return;
  291. sendClipboardData(data);
  292. } catch(rdr::Exception& e) {
  293. close(e.str());
  294. }
  295. }
  296. bool VNCSConnectionST::getComparerState()
  297. {
  298. // We interpret a low compression level as an indication that the client
  299. // wants to prioritise CPU usage over bandwidth, and hence disable the
  300. // comparing update tracker.
  301. return (client.compressLevel == -1) || (client.compressLevel > 1);
  302. }
  303. // renderedCursorChange() is called whenever the server-side rendered cursor
  304. // changes shape or position. It ensures that the next update will clean up
  305. // the old rendered cursor and if necessary draw the new rendered cursor.
  306. void VNCSConnectionST::renderedCursorChange()
  307. {
  308. if (state() != RFBSTATE_NORMAL) return;
  309. // Are we switching between client-side and server-side cursor?
  310. if (clientHasCursor == needRenderedCursor())
  311. setCursorOrClose();
  312. bool hasRenderedCursor = !damagedCursorRegion.is_empty();
  313. if (hasRenderedCursor)
  314. removeRenderedCursor = true;
  315. if (needRenderedCursor()) {
  316. updateRenderedCursor = true;
  317. writeFramebufferUpdateOrClose();
  318. }
  319. }
  320. // needRenderedCursor() returns true if this client needs the server-side
  321. // rendered cursor. This may be because it does not support local cursor or
  322. // because the current cursor position has not been set by this client.
  323. // Unfortunately we can't know for sure when the current cursor position has
  324. // been set by this client. We guess that this is the case when the current
  325. // cursor position is the same as the last pointer event from this client, or
  326. // if it is a very short time since this client's last pointer event (up to a
  327. // second). [ Ideally we should do finer-grained timing here and make the time
  328. // configurable, but I don't think it's that important. ]
  329. bool VNCSConnectionST::needRenderedCursor()
  330. {
  331. if (state() != RFBSTATE_NORMAL)
  332. return false;
  333. if (!client.supportsLocalCursor())
  334. return true;
  335. if (!server->getCursorPos().equals(pointerEventPos) &&
  336. (time(0) - pointerEventTime) > 0)
  337. return true;
  338. return false;
  339. }
  340. void VNCSConnectionST::approveConnectionOrClose(bool accept,
  341. const char* reason)
  342. {
  343. try {
  344. approveConnection(accept, reason);
  345. } catch (rdr::Exception& e) {
  346. close(e.str());
  347. }
  348. }
  349. // -=- Callbacks from SConnection
  350. void VNCSConnectionST::authSuccess()
  351. {
  352. if (rfb::Server::idleTimeout)
  353. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  354. // - Set the connection parameters appropriately
  355. client.setDimensions(server->getPixelBuffer()->width(),
  356. server->getPixelBuffer()->height(),
  357. server->getScreenLayout());
  358. client.setName(server->getName());
  359. client.setLEDState(server->getLEDState());
  360. // - Set the default pixel format
  361. client.setPF(server->getPixelBuffer()->getPF());
  362. char buffer[256];
  363. client.pf().print(buffer, 256);
  364. vlog.info("Server default pixel format %s", buffer);
  365. // - Mark the entire display as "dirty"
  366. updates.add_changed(server->getPixelBuffer()->getRect());
  367. }
  368. void VNCSConnectionST::queryConnection(const char* userName)
  369. {
  370. server->queryConnection(this, userName);
  371. }
  372. void VNCSConnectionST::clientInit(bool shared)
  373. {
  374. if (rfb::Server::idleTimeout)
  375. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  376. if (rfb::Server::alwaysShared || reverseConnection) shared = true;
  377. if (!accessCheck(AccessNonShared)) shared = true;
  378. if (rfb::Server::neverShared) shared = false;
  379. SConnection::clientInit(shared);
  380. server->clientReady(this, shared);
  381. }
  382. void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
  383. {
  384. SConnection::setPixelFormat(pf);
  385. char buffer[256];
  386. pf.print(buffer, 256);
  387. vlog.info("Client pixel format %s", buffer);
  388. setCursor();
  389. }
  390. void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
  391. {
  392. if (rfb::Server::idleTimeout)
  393. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  394. pointerEventTime = time(0);
  395. if (!accessCheck(AccessPtrEvents)) return;
  396. if (!rfb::Server::acceptPointerEvents) return;
  397. pointerEventPos = pos;
  398. server->pointerEvent(this, pointerEventPos, buttonMask);
  399. }
  400. class VNCSConnectionSTShiftPresser {
  401. public:
  402. VNCSConnectionSTShiftPresser(VNCServerST* server_)
  403. : server(server_), pressed(false) {}
  404. ~VNCSConnectionSTShiftPresser() {
  405. if (pressed) {
  406. vlog.debug("Releasing fake Shift_L");
  407. server->keyEvent(XK_Shift_L, 0, false);
  408. }
  409. }
  410. void press() {
  411. vlog.debug("Pressing fake Shift_L");
  412. server->keyEvent(XK_Shift_L, 0, true);
  413. pressed = true;
  414. }
  415. VNCServerST* server;
  416. bool pressed;
  417. };
  418. // keyEvent() - record in the pressedKeys which keys were pressed. Allow
  419. // multiple down events (for autorepeat), but only allow a single up event.
  420. void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
  421. rdr::U32 lookup;
  422. if (rfb::Server::idleTimeout)
  423. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  424. if (!accessCheck(AccessKeyEvents)) return;
  425. if (!rfb::Server::acceptKeyEvents) return;
  426. if (down)
  427. vlog.debug("Key pressed: 0x%x / 0x%x", keysym, keycode);
  428. else
  429. vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);
  430. // Avoid lock keys if we don't know the server state
  431. if ((server->getLEDState() == ledUnknown) &&
  432. ((keysym == XK_Caps_Lock) ||
  433. (keysym == XK_Num_Lock))) {
  434. vlog.debug("Ignoring lock key (e.g. caps lock)");
  435. return;
  436. }
  437. // Lock key heuristics
  438. // (only for clients that do not support the LED state extension)
  439. if (!client.supportsLEDState()) {
  440. if (down && (server->getLEDState() != ledUnknown)) {
  441. // CapsLock synchronisation heuristic
  442. // (this assumes standard interaction between CapsLock the Shift
  443. // keys and normal characters)
  444. if (((keysym >= XK_A) && (keysym <= XK_Z)) ||
  445. ((keysym >= XK_a) && (keysym <= XK_z))) {
  446. bool uppercase, shift, lock;
  447. uppercase = (keysym >= XK_A) && (keysym <= XK_Z);
  448. shift = isShiftPressed();
  449. lock = server->getLEDState() & ledCapsLock;
  450. if (lock == (uppercase == shift)) {
  451. vlog.debug("Inserting fake CapsLock to get in sync with client");
  452. server->keyEvent(XK_Caps_Lock, 0, true);
  453. server->keyEvent(XK_Caps_Lock, 0, false);
  454. }
  455. }
  456. // NumLock synchronisation heuristic
  457. // (this is more cautious because of the differences between Unix,
  458. // Windows and macOS)
  459. if (((keysym >= XK_KP_Home) && (keysym <= XK_KP_Delete)) ||
  460. ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  461. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal)) {
  462. bool number, shift, lock;
  463. number = ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  464. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal);
  465. shift = isShiftPressed();
  466. lock = server->getLEDState() & ledNumLock;
  467. if (shift) {
  468. // We don't know the appropriate NumLock state for when Shift
  469. // is pressed as it could be one of:
  470. //
  471. // a) A Unix client where Shift negates NumLock
  472. //
  473. // b) A Windows client where Shift only cancels NumLock
  474. //
  475. // c) A macOS client where Shift doesn't have any effect
  476. //
  477. } else if (lock == (number == shift)) {
  478. vlog.debug("Inserting fake NumLock to get in sync with client");
  479. server->keyEvent(XK_Num_Lock, 0, true);
  480. server->keyEvent(XK_Num_Lock, 0, false);
  481. }
  482. }
  483. }
  484. }
  485. // Turn ISO_Left_Tab into shifted Tab.
  486. VNCSConnectionSTShiftPresser shiftPresser(server);
  487. if (keysym == XK_ISO_Left_Tab) {
  488. if (!isShiftPressed())
  489. shiftPresser.press();
  490. keysym = XK_Tab;
  491. }
  492. // We need to be able to track keys, so generate a fake index when we
  493. // aren't given a keycode
  494. if (keycode == 0)
  495. lookup = 0x80000000 | keysym;
  496. else
  497. lookup = keycode;
  498. // We force the same keysym for an already down key for the
  499. // sake of sanity
  500. if (pressedKeys.find(lookup) != pressedKeys.end())
  501. keysym = pressedKeys[lookup];
  502. if (down) {
  503. pressedKeys[lookup] = keysym;
  504. } else {
  505. if (!pressedKeys.erase(lookup))
  506. return;
  507. }
  508. server->keyEvent(keysym, keycode, down);
  509. }
  510. void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
  511. {
  512. Rect safeRect;
  513. if (!accessCheck(AccessView)) return;
  514. SConnection::framebufferUpdateRequest(r, incremental);
  515. // Check that the client isn't sending crappy requests
  516. if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) {
  517. vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
  518. r.width(), r.height(), r.tl.x, r.tl.y,
  519. client.width(), client.height());
  520. safeRect = r.intersect(Rect(0, 0, client.width(), client.height()));
  521. } else {
  522. safeRect = r;
  523. }
  524. // Just update the requested region.
  525. // Framebuffer update will be sent a bit later, see processMessages().
  526. Region reqRgn(r);
  527. if (!incremental || !continuousUpdates)
  528. requested.assign_union(reqRgn);
  529. if (!incremental) {
  530. // Non-incremental update - treat as if area requested has changed
  531. updates.add_changed(reqRgn);
  532. // And send the screen layout to the client (which, unlike the
  533. // framebuffer dimensions, the client doesn't get during init)
  534. if (client.supportsEncoding(pseudoEncodingExtendedDesktopSize))
  535. writer()->writeDesktopSize(reasonServer);
  536. // We do not send a DesktopSize since it only contains the
  537. // framebuffer size (which the client already should know) and
  538. // because some clients don't handle extra DesktopSize events
  539. // very well.
  540. }
  541. }
  542. void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
  543. const ScreenSet& layout)
  544. {
  545. unsigned int result;
  546. if (!accessCheck(AccessSetDesktopSize)) return;
  547. if (!rfb::Server::acceptSetDesktopSize) return;
  548. result = server->setDesktopSize(this, fb_width, fb_height, layout);
  549. writer()->writeDesktopSize(reasonClient, result);
  550. }
  551. void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
  552. {
  553. rdr::U8 type;
  554. if (flags & fenceFlagRequest) {
  555. if (flags & fenceFlagSyncNext) {
  556. pendingSyncFence = true;
  557. fenceFlags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter | fenceFlagSyncNext);
  558. fenceDataLen = len;
  559. delete [] fenceData;
  560. fenceData = NULL;
  561. if (len > 0) {
  562. fenceData = new char[len];
  563. memcpy(fenceData, data, len);
  564. }
  565. return;
  566. }
  567. // We handle everything synchronously so we trivially honor these modes
  568. flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter);
  569. writer()->writeFence(flags, len, data);
  570. return;
  571. }
  572. if (len < 1)
  573. vlog.error("Fence response of unexpected size received");
  574. type = data[0];
  575. switch (type) {
  576. case 0:
  577. // Initial dummy fence;
  578. break;
  579. case 1:
  580. congestion.gotPong();
  581. break;
  582. default:
  583. vlog.error("Fence response of unexpected type received");
  584. }
  585. }
  586. void VNCSConnectionST::enableContinuousUpdates(bool enable,
  587. int x, int y, int w, int h)
  588. {
  589. Rect rect;
  590. if (!client.supportsFence() || !client.supportsContinuousUpdates())
  591. throw Exception("Client tried to enable continuous updates when not allowed");
  592. continuousUpdates = enable;
  593. rect.setXYWH(x, y, w, h);
  594. cuRegion.reset(rect);
  595. if (enable) {
  596. requested.clear();
  597. } else {
  598. writer()->writeEndOfContinuousUpdates();
  599. }
  600. }
  601. void VNCSConnectionST::handleClipboardRequest()
  602. {
  603. if (!accessCheck(AccessCutText)) return;
  604. server->handleClipboardRequest(this);
  605. }
  606. void VNCSConnectionST::handleClipboardAnnounce(bool available)
  607. {
  608. if (!accessCheck(AccessCutText)) return;
  609. if (!rfb::Server::acceptCutText) return;
  610. server->handleClipboardAnnounce(this, available);
  611. }
  612. void VNCSConnectionST::handleClipboardData(const char* data)
  613. {
  614. if (!accessCheck(AccessCutText)) return;
  615. if (!rfb::Server::acceptCutText) return;
  616. server->handleClipboardData(this, data);
  617. }
  618. // supportsLocalCursor() is called whenever the status of
  619. // client.supportsLocalCursor() has changed. If the client does now support local
  620. // cursor, we make sure that the old server-side rendered cursor is cleaned up
  621. // and the cursor is sent to the client.
  622. void VNCSConnectionST::supportsLocalCursor()
  623. {
  624. bool hasRenderedCursor = !damagedCursorRegion.is_empty();
  625. if (hasRenderedCursor && !needRenderedCursor())
  626. removeRenderedCursor = true;
  627. setCursor();
  628. }
  629. void VNCSConnectionST::supportsFence()
  630. {
  631. char type = 0;
  632. writer()->writeFence(fenceFlagRequest, sizeof(type), &type);
  633. }
  634. void VNCSConnectionST::supportsContinuousUpdates()
  635. {
  636. // We refuse to use continuous updates if we cannot monitor the buffer
  637. // usage using fences.
  638. if (!client.supportsFence())
  639. return;
  640. writer()->writeEndOfContinuousUpdates();
  641. }
  642. void VNCSConnectionST::supportsLEDState()
  643. {
  644. if (client.ledState() == ledUnknown)
  645. return;
  646. writer()->writeLEDState();
  647. }
  648. bool VNCSConnectionST::handleTimeout(Timer* t)
  649. {
  650. try {
  651. if ((t == &congestionTimer) ||
  652. (t == &losslessTimer))
  653. writeFramebufferUpdate();
  654. } catch (rdr::Exception& e) {
  655. close(e.str());
  656. }
  657. if (t == &idleTimer)
  658. close("Idle timeout");
  659. return false;
  660. }
  661. bool VNCSConnectionST::isShiftPressed()
  662. {
  663. std::map<rdr::U32, rdr::U32>::const_iterator iter;
  664. for (iter = pressedKeys.begin(); iter != pressedKeys.end(); ++iter) {
  665. if (iter->second == XK_Shift_L)
  666. return true;
  667. if (iter->second == XK_Shift_R)
  668. return true;
  669. }
  670. return false;
  671. }
  672. void VNCSConnectionST::writeRTTPing()
  673. {
  674. char type;
  675. if (!client.supportsFence())
  676. return;
  677. congestion.updatePosition(sock->outStream().length());
  678. // We need to make sure any old update are already processed by the
  679. // time we get the response back. This allows us to reliably throttle
  680. // back on client overload, as well as network overload.
  681. type = 1;
  682. writer()->writeFence(fenceFlagRequest | fenceFlagBlockBefore,
  683. sizeof(type), &type);
  684. congestion.sentPing();
  685. }
  686. bool VNCSConnectionST::isCongested()
  687. {
  688. int eta;
  689. congestionTimer.stop();
  690. // Stuff still waiting in the send buffer?
  691. sock->outStream().flush();
  692. congestion.debugTrace("congestion-trace.csv", sock->getFd());
  693. if (sock->outStream().hasBufferedData())
  694. return true;
  695. if (!client.supportsFence())
  696. return false;
  697. congestion.updatePosition(sock->outStream().length());
  698. if (!congestion.isCongested())
  699. return false;
  700. eta = congestion.getUncongestedETA();
  701. if (eta >= 0)
  702. congestionTimer.start(eta);
  703. return true;
  704. }
  705. void VNCSConnectionST::writeFramebufferUpdate()
  706. {
  707. congestion.updatePosition(sock->outStream().length());
  708. // We're in the middle of processing a command that's supposed to be
  709. // synchronised. Allowing an update to slip out right now might violate
  710. // that synchronisation.
  711. if (syncFence)
  712. return;
  713. // We try to aggregate responses, so don't send out anything whilst we
  714. // still have incoming messages. processMessages() will give us another
  715. // chance to run once things are idle.
  716. if (inProcessMessages)
  717. return;
  718. if (state() != RFBSTATE_NORMAL)
  719. return;
  720. if (requested.is_empty() && !continuousUpdates)
  721. return;
  722. // Check that we actually have some space on the link and retry in a
  723. // bit if things are congested.
  724. if (isCongested())
  725. return;
  726. // Updates often consists of many small writes, and in continuous
  727. // mode, we will also have small fence messages around the update. We
  728. // need to aggregate these in order to not clog up TCP's congestion
  729. // window.
  730. getOutStream()->cork(true);
  731. // First take care of any updates that cannot contain framebuffer data
  732. // changes.
  733. writeNoDataUpdate();
  734. // Then real data (if possible)
  735. writeDataUpdate();
  736. getOutStream()->cork(false);
  737. congestion.updatePosition(sock->outStream().length());
  738. }
  739. void VNCSConnectionST::writeNoDataUpdate()
  740. {
  741. if (!writer()->needNoDataUpdate())
  742. return;
  743. writer()->writeNoDataUpdate();
  744. // Make sure no data update is sent until next request
  745. requested.clear();
  746. }
  747. void VNCSConnectionST::writeDataUpdate()
  748. {
  749. Region req;
  750. UpdateInfo ui;
  751. bool needNewUpdateInfo;
  752. const RenderedCursor *cursor;
  753. // See what the client has requested (if anything)
  754. if (continuousUpdates)
  755. req = cuRegion.union_(requested);
  756. else
  757. req = requested;
  758. if (req.is_empty())
  759. return;
  760. // Get the lists of updates. Prior to exporting the data to the `ui' object,
  761. // getUpdateInfo() will normalize the `updates' object such way that its
  762. // `changed' and `copied' regions would not intersect.
  763. updates.getUpdateInfo(&ui, req);
  764. needNewUpdateInfo = false;
  765. // If the previous position of the rendered cursor overlaps the source of the
  766. // copy, then when the copy happens the corresponding rectangle in the
  767. // destination will be wrong, so add it to the changed region.
  768. if (!ui.copied.is_empty() && !damagedCursorRegion.is_empty()) {
  769. Region bogusCopiedCursor;
  770. bogusCopiedCursor = damagedCursorRegion;
  771. bogusCopiedCursor.translate(ui.copy_delta);
  772. bogusCopiedCursor.assign_intersect(server->getPixelBuffer()->getRect());
  773. if (!ui.copied.intersect(bogusCopiedCursor).is_empty()) {
  774. updates.add_changed(bogusCopiedCursor);
  775. needNewUpdateInfo = true;
  776. }
  777. }
  778. // If we need to remove the old rendered cursor, just add the region to
  779. // the changed region.
  780. if (removeRenderedCursor) {
  781. updates.add_changed(damagedCursorRegion);
  782. needNewUpdateInfo = true;
  783. damagedCursorRegion.clear();
  784. removeRenderedCursor = false;
  785. }
  786. // If we need a full cursor update then make sure its entire region
  787. // is marked as changed.
  788. if (updateRenderedCursor) {
  789. updates.add_changed(server->getRenderedCursor()->getEffectiveRect());
  790. needNewUpdateInfo = true;
  791. updateRenderedCursor = false;
  792. }
  793. // The `updates' object could change, make sure we have valid update info.
  794. if (needNewUpdateInfo)
  795. updates.getUpdateInfo(&ui, req);
  796. // If there are queued updates then we cannot safely send an update
  797. // without risking a partially updated screen
  798. if (!server->getPendingRegion().is_empty()) {
  799. req.clear();
  800. ui.changed.clear();
  801. ui.copied.clear();
  802. }
  803. // Does the client need a server-side rendered cursor?
  804. cursor = NULL;
  805. if (needRenderedCursor()) {
  806. Rect renderedCursorRect;
  807. cursor = server->getRenderedCursor();
  808. renderedCursorRect = cursor->getEffectiveRect();
  809. // Check that we don't try to copy over the cursor area, and
  810. // if that happens we need to treat it as changed so that we can
  811. // re-render it
  812. if (!ui.copied.intersect(renderedCursorRect).is_empty()) {
  813. ui.changed.assign_union(ui.copied.intersect(renderedCursorRect));
  814. ui.copied.assign_subtract(renderedCursorRect);
  815. }
  816. // Track where we've rendered the cursor
  817. damagedCursorRegion.assign_union(ui.changed.intersect(renderedCursorRect));
  818. }
  819. // If we don't have a normal update, then try a lossless refresh
  820. if (ui.is_empty() && !writer()->needFakeUpdate()) {
  821. writeLosslessRefresh();
  822. return;
  823. }
  824. // We have something to send, so let's get to it
  825. writeRTTPing();
  826. encodeManager.writeUpdate(ui, server->getPixelBuffer(), cursor);
  827. writeRTTPing();
  828. // The request might be for just part of the screen, so we cannot
  829. // just clear the entire update tracker.
  830. updates.subtract(req);
  831. requested.clear();
  832. }
  833. void VNCSConnectionST::writeLosslessRefresh()
  834. {
  835. Region req, pending;
  836. const RenderedCursor *cursor;
  837. int nextRefresh, nextUpdate;
  838. size_t bandwidth, maxUpdateSize;
  839. if (continuousUpdates)
  840. req = cuRegion.union_(requested);
  841. else
  842. req = requested;
  843. // If there are queued updates then we could not safely send an
  844. // update without risking a partially updated screen, however we
  845. // might still be able to send a lossless refresh
  846. pending = server->getPendingRegion();
  847. if (!pending.is_empty()) {
  848. UpdateInfo ui;
  849. // Don't touch the updates pending in the server core
  850. req.assign_subtract(pending);
  851. // Or any updates pending just for this connection
  852. updates.getUpdateInfo(&ui, req);
  853. req.assign_subtract(ui.changed);
  854. req.assign_subtract(ui.copied);
  855. }
  856. // Any lossy area we can refresh?
  857. if (!encodeManager.needsLosslessRefresh(req))
  858. return;
  859. // Right away? Or later?
  860. nextRefresh = encodeManager.getNextLosslessRefresh(req);
  861. if (nextRefresh > 0) {
  862. losslessTimer.start(nextRefresh);
  863. return;
  864. }
  865. // Prepare the cursor in case it overlaps with a region getting
  866. // refreshed
  867. cursor = NULL;
  868. if (needRenderedCursor())
  869. cursor = server->getRenderedCursor();
  870. // FIXME: If continuous updates aren't used then the client might
  871. // be slower than frameRate in its requests and we could
  872. // afford a larger update size
  873. nextUpdate = server->msToNextUpdate();
  874. // Don't bother if we're about to send a real update
  875. if (nextUpdate == 0)
  876. return;
  877. // FIXME: Bandwidth estimation without congestion control
  878. bandwidth = congestion.getBandwidth();
  879. // FIXME: Hard coded value for maximum CPU throughput
  880. if (bandwidth > 5000000)
  881. bandwidth = 5000000;
  882. maxUpdateSize = bandwidth * nextUpdate / 1000;
  883. writeRTTPing();
  884. encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
  885. cursor, maxUpdateSize);
  886. writeRTTPing();
  887. requested.clear();
  888. }
  889. void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
  890. {
  891. if (!authenticated())
  892. return;
  893. client.setDimensions(client.width(), client.height(),
  894. server->getScreenLayout());
  895. if (state() != RFBSTATE_NORMAL)
  896. return;
  897. writer()->writeDesktopSize(reason);
  898. }
  899. // setCursor() is called whenever the cursor has changed shape or pixel format.
  900. // If the client supports local cursor then it will arrange for the cursor to
  901. // be sent to the client.
  902. void VNCSConnectionST::setCursor()
  903. {
  904. if (state() != RFBSTATE_NORMAL)
  905. return;
  906. // We need to blank out the client's cursor or there will be two
  907. if (needRenderedCursor()) {
  908. client.setCursor(emptyCursor);
  909. clientHasCursor = false;
  910. } else {
  911. client.setCursor(*server->getCursor());
  912. clientHasCursor = true;
  913. }
  914. if (client.supportsLocalCursor())
  915. writer()->writeCursor();
  916. }
  917. void VNCSConnectionST::setDesktopName(const char *name)
  918. {
  919. client.setName(name);
  920. if (state() != RFBSTATE_NORMAL)
  921. return;
  922. if (client.supportsEncoding(pseudoEncodingDesktopName))
  923. writer()->writeSetDesktopName();
  924. }
  925. void VNCSConnectionST::setLEDState(unsigned int ledstate)
  926. {
  927. if (state() != RFBSTATE_NORMAL)
  928. return;
  929. client.setLEDState(ledstate);
  930. if (client.supportsLEDState())
  931. writer()->writeLEDState();
  932. }