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 33KB

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