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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  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. // cursorPositionChange() is called whenever the cursor has changed position by
  321. // the server. If the client supports being informed about these changes then
  322. // it will arrange for the new cursor position to be sent to the client.
  323. void VNCSConnectionST::cursorPositionChange()
  324. {
  325. setCursorPos();
  326. }
  327. // needRenderedCursor() returns true if this client needs the server-side
  328. // rendered cursor. This may be because it does not support local cursor or
  329. // because the current cursor position has not been set by this client.
  330. // Unfortunately we can't know for sure when the current cursor position has
  331. // been set by this client. We guess that this is the case when the current
  332. // cursor position is the same as the last pointer event from this client, or
  333. // if it is a very short time since this client's last pointer event (up to a
  334. // second). [ Ideally we should do finer-grained timing here and make the time
  335. // configurable, but I don't think it's that important. ]
  336. bool VNCSConnectionST::needRenderedCursor()
  337. {
  338. if (state() != RFBSTATE_NORMAL)
  339. return false;
  340. if (!client.supportsLocalCursor())
  341. return true;
  342. if (!server->getCursorPos().equals(pointerEventPos) &&
  343. (time(0) - pointerEventTime) > 0)
  344. return true;
  345. return false;
  346. }
  347. void VNCSConnectionST::approveConnectionOrClose(bool accept,
  348. const char* reason)
  349. {
  350. try {
  351. approveConnection(accept, reason);
  352. } catch (rdr::Exception& e) {
  353. close(e.str());
  354. }
  355. }
  356. // -=- Callbacks from SConnection
  357. void VNCSConnectionST::authSuccess()
  358. {
  359. if (rfb::Server::idleTimeout)
  360. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  361. // - Set the connection parameters appropriately
  362. client.setDimensions(server->getPixelBuffer()->width(),
  363. server->getPixelBuffer()->height(),
  364. server->getScreenLayout());
  365. client.setName(server->getName());
  366. client.setLEDState(server->getLEDState());
  367. // - Set the default pixel format
  368. client.setPF(server->getPixelBuffer()->getPF());
  369. char buffer[256];
  370. client.pf().print(buffer, 256);
  371. vlog.info("Server default pixel format %s", buffer);
  372. // - Mark the entire display as "dirty"
  373. updates.add_changed(server->getPixelBuffer()->getRect());
  374. }
  375. void VNCSConnectionST::queryConnection(const char* userName)
  376. {
  377. server->queryConnection(this, userName);
  378. }
  379. void VNCSConnectionST::clientInit(bool shared)
  380. {
  381. if (rfb::Server::idleTimeout)
  382. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  383. if (rfb::Server::alwaysShared || reverseConnection) shared = true;
  384. if (!accessCheck(AccessNonShared)) shared = true;
  385. if (rfb::Server::neverShared) shared = false;
  386. SConnection::clientInit(shared);
  387. server->clientReady(this, shared);
  388. }
  389. void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
  390. {
  391. SConnection::setPixelFormat(pf);
  392. char buffer[256];
  393. pf.print(buffer, 256);
  394. vlog.info("Client pixel format %s", buffer);
  395. setCursor();
  396. }
  397. void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
  398. {
  399. if (rfb::Server::idleTimeout)
  400. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  401. pointerEventTime = time(0);
  402. if (!accessCheck(AccessPtrEvents)) return;
  403. if (!rfb::Server::acceptPointerEvents) return;
  404. pointerEventPos = pos;
  405. server->pointerEvent(this, pointerEventPos, buttonMask);
  406. }
  407. class VNCSConnectionSTShiftPresser {
  408. public:
  409. VNCSConnectionSTShiftPresser(VNCServerST* server_)
  410. : server(server_), pressed(false) {}
  411. ~VNCSConnectionSTShiftPresser() {
  412. if (pressed) {
  413. vlog.debug("Releasing fake Shift_L");
  414. server->keyEvent(XK_Shift_L, 0, false);
  415. }
  416. }
  417. void press() {
  418. vlog.debug("Pressing fake Shift_L");
  419. server->keyEvent(XK_Shift_L, 0, true);
  420. pressed = true;
  421. }
  422. VNCServerST* server;
  423. bool pressed;
  424. };
  425. // keyEvent() - record in the pressedKeys which keys were pressed. Allow
  426. // multiple down events (for autorepeat), but only allow a single up event.
  427. void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
  428. rdr::U32 lookup;
  429. if (rfb::Server::idleTimeout)
  430. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  431. if (!accessCheck(AccessKeyEvents)) return;
  432. if (!rfb::Server::acceptKeyEvents) return;
  433. if (down)
  434. vlog.debug("Key pressed: 0x%x / 0x%x", keysym, keycode);
  435. else
  436. vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);
  437. // Avoid lock keys if we don't know the server state
  438. if ((server->getLEDState() == ledUnknown) &&
  439. ((keysym == XK_Caps_Lock) ||
  440. (keysym == XK_Num_Lock))) {
  441. vlog.debug("Ignoring lock key (e.g. caps lock)");
  442. return;
  443. }
  444. // Lock key heuristics
  445. // (only for clients that do not support the LED state extension)
  446. if (!client.supportsLEDState()) {
  447. if (down && (server->getLEDState() != ledUnknown)) {
  448. // CapsLock synchronisation heuristic
  449. // (this assumes standard interaction between CapsLock the Shift
  450. // keys and normal characters)
  451. if (((keysym >= XK_A) && (keysym <= XK_Z)) ||
  452. ((keysym >= XK_a) && (keysym <= XK_z))) {
  453. bool uppercase, shift, lock;
  454. uppercase = (keysym >= XK_A) && (keysym <= XK_Z);
  455. shift = isShiftPressed();
  456. lock = server->getLEDState() & ledCapsLock;
  457. if (lock == (uppercase == shift)) {
  458. vlog.debug("Inserting fake CapsLock to get in sync with client");
  459. server->keyEvent(XK_Caps_Lock, 0, true);
  460. server->keyEvent(XK_Caps_Lock, 0, false);
  461. }
  462. }
  463. // NumLock synchronisation heuristic
  464. // (this is more cautious because of the differences between Unix,
  465. // Windows and macOS)
  466. if (((keysym >= XK_KP_Home) && (keysym <= XK_KP_Delete)) ||
  467. ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  468. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal)) {
  469. bool number, shift, lock;
  470. number = ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  471. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal);
  472. shift = isShiftPressed();
  473. lock = server->getLEDState() & ledNumLock;
  474. if (shift) {
  475. // We don't know the appropriate NumLock state for when Shift
  476. // is pressed as it could be one of:
  477. //
  478. // a) A Unix client where Shift negates NumLock
  479. //
  480. // b) A Windows client where Shift only cancels NumLock
  481. //
  482. // c) A macOS client where Shift doesn't have any effect
  483. //
  484. } else if (lock == (number == shift)) {
  485. vlog.debug("Inserting fake NumLock to get in sync with client");
  486. server->keyEvent(XK_Num_Lock, 0, true);
  487. server->keyEvent(XK_Num_Lock, 0, false);
  488. }
  489. }
  490. }
  491. }
  492. // Turn ISO_Left_Tab into shifted Tab.
  493. VNCSConnectionSTShiftPresser shiftPresser(server);
  494. if (keysym == XK_ISO_Left_Tab) {
  495. if (!isShiftPressed())
  496. shiftPresser.press();
  497. keysym = XK_Tab;
  498. }
  499. // We need to be able to track keys, so generate a fake index when we
  500. // aren't given a keycode
  501. if (keycode == 0)
  502. lookup = 0x80000000 | keysym;
  503. else
  504. lookup = keycode;
  505. // We force the same keysym for an already down key for the
  506. // sake of sanity
  507. if (pressedKeys.find(lookup) != pressedKeys.end())
  508. keysym = pressedKeys[lookup];
  509. if (down) {
  510. pressedKeys[lookup] = keysym;
  511. } else {
  512. if (!pressedKeys.erase(lookup))
  513. return;
  514. }
  515. server->keyEvent(keysym, keycode, down);
  516. }
  517. void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
  518. {
  519. Rect safeRect;
  520. if (!accessCheck(AccessView)) return;
  521. SConnection::framebufferUpdateRequest(r, incremental);
  522. // Check that the client isn't sending crappy requests
  523. if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) {
  524. vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
  525. r.width(), r.height(), r.tl.x, r.tl.y,
  526. client.width(), client.height());
  527. safeRect = r.intersect(Rect(0, 0, client.width(), client.height()));
  528. } else {
  529. safeRect = r;
  530. }
  531. // Just update the requested region.
  532. // Framebuffer update will be sent a bit later, see processMessages().
  533. Region reqRgn(safeRect);
  534. if (!incremental || !continuousUpdates)
  535. requested.assign_union(reqRgn);
  536. if (!incremental) {
  537. // Non-incremental update - treat as if area requested has changed
  538. updates.add_changed(reqRgn);
  539. // And send the screen layout to the client (which, unlike the
  540. // framebuffer dimensions, the client doesn't get during init)
  541. if (client.supportsEncoding(pseudoEncodingExtendedDesktopSize))
  542. writer()->writeDesktopSize(reasonServer);
  543. // We do not send a DesktopSize since it only contains the
  544. // framebuffer size (which the client already should know) and
  545. // because some clients don't handle extra DesktopSize events
  546. // very well.
  547. }
  548. }
  549. void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
  550. const ScreenSet& layout)
  551. {
  552. unsigned int result;
  553. if (!accessCheck(AccessSetDesktopSize) || !rfb::Server::acceptSetDesktopSize)
  554. result = resultProhibited;
  555. else
  556. result = server->setDesktopSize(this, fb_width, fb_height, layout);
  557. writer()->writeDesktopSize(reasonClient, result);
  558. }
  559. void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
  560. {
  561. rdr::U8 type;
  562. if (flags & fenceFlagRequest) {
  563. if (flags & fenceFlagSyncNext) {
  564. pendingSyncFence = true;
  565. fenceFlags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter | fenceFlagSyncNext);
  566. fenceDataLen = len;
  567. delete [] fenceData;
  568. fenceData = NULL;
  569. if (len > 0) {
  570. fenceData = new char[len];
  571. memcpy(fenceData, data, len);
  572. }
  573. return;
  574. }
  575. // We handle everything synchronously so we trivially honor these modes
  576. flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter);
  577. writer()->writeFence(flags, len, data);
  578. return;
  579. }
  580. if (len < 1)
  581. vlog.error("Fence response of unexpected size received");
  582. type = data[0];
  583. switch (type) {
  584. case 0:
  585. // Initial dummy fence;
  586. break;
  587. case 1:
  588. congestion.gotPong();
  589. break;
  590. default:
  591. vlog.error("Fence response of unexpected type received");
  592. }
  593. }
  594. void VNCSConnectionST::enableContinuousUpdates(bool enable,
  595. int x, int y, int w, int h)
  596. {
  597. Rect rect;
  598. if (!client.supportsFence() || !client.supportsContinuousUpdates())
  599. throw Exception("Client tried to enable continuous updates when not allowed");
  600. continuousUpdates = enable;
  601. rect.setXYWH(x, y, w, h);
  602. cuRegion.reset(rect);
  603. if (enable) {
  604. requested.clear();
  605. } else {
  606. writer()->writeEndOfContinuousUpdates();
  607. }
  608. }
  609. void VNCSConnectionST::handleClipboardRequest()
  610. {
  611. if (!accessCheck(AccessCutText)) return;
  612. server->handleClipboardRequest(this);
  613. }
  614. void VNCSConnectionST::handleClipboardAnnounce(bool available)
  615. {
  616. if (!accessCheck(AccessCutText)) return;
  617. if (!rfb::Server::acceptCutText) return;
  618. server->handleClipboardAnnounce(this, available);
  619. }
  620. void VNCSConnectionST::handleClipboardData(const char* data)
  621. {
  622. if (!accessCheck(AccessCutText)) return;
  623. if (!rfb::Server::acceptCutText) return;
  624. server->handleClipboardData(this, data);
  625. }
  626. // supportsLocalCursor() is called whenever the status of
  627. // client.supportsLocalCursor() has changed. If the client does now support local
  628. // cursor, we make sure that the old server-side rendered cursor is cleaned up
  629. // and the cursor is sent to the client.
  630. void VNCSConnectionST::supportsLocalCursor()
  631. {
  632. bool hasRenderedCursor = !damagedCursorRegion.is_empty();
  633. if (hasRenderedCursor && !needRenderedCursor())
  634. removeRenderedCursor = true;
  635. setCursor();
  636. }
  637. void VNCSConnectionST::supportsFence()
  638. {
  639. char type = 0;
  640. writer()->writeFence(fenceFlagRequest, sizeof(type), &type);
  641. }
  642. void VNCSConnectionST::supportsContinuousUpdates()
  643. {
  644. // We refuse to use continuous updates if we cannot monitor the buffer
  645. // usage using fences.
  646. if (!client.supportsFence())
  647. return;
  648. writer()->writeEndOfContinuousUpdates();
  649. }
  650. void VNCSConnectionST::supportsLEDState()
  651. {
  652. if (client.ledState() == ledUnknown)
  653. return;
  654. writer()->writeLEDState();
  655. }
  656. bool VNCSConnectionST::handleTimeout(Timer* t)
  657. {
  658. try {
  659. if ((t == &congestionTimer) ||
  660. (t == &losslessTimer))
  661. writeFramebufferUpdate();
  662. } catch (rdr::Exception& e) {
  663. close(e.str());
  664. }
  665. if (t == &idleTimer)
  666. close("Idle timeout");
  667. return false;
  668. }
  669. bool VNCSConnectionST::isShiftPressed()
  670. {
  671. std::map<rdr::U32, rdr::U32>::const_iterator iter;
  672. for (iter = pressedKeys.begin(); iter != pressedKeys.end(); ++iter) {
  673. if (iter->second == XK_Shift_L)
  674. return true;
  675. if (iter->second == XK_Shift_R)
  676. return true;
  677. }
  678. return false;
  679. }
  680. void VNCSConnectionST::writeRTTPing()
  681. {
  682. char type;
  683. if (!client.supportsFence())
  684. return;
  685. congestion.updatePosition(sock->outStream().length());
  686. // We need to make sure any old update are already processed by the
  687. // time we get the response back. This allows us to reliably throttle
  688. // back on client overload, as well as network overload.
  689. type = 1;
  690. writer()->writeFence(fenceFlagRequest | fenceFlagBlockBefore,
  691. sizeof(type), &type);
  692. congestion.sentPing();
  693. }
  694. bool VNCSConnectionST::isCongested()
  695. {
  696. int eta;
  697. congestionTimer.stop();
  698. // Stuff still waiting in the send buffer?
  699. sock->outStream().flush();
  700. congestion.debugTrace("congestion-trace.csv", sock->getFd());
  701. if (sock->outStream().hasBufferedData())
  702. return true;
  703. if (!client.supportsFence())
  704. return false;
  705. congestion.updatePosition(sock->outStream().length());
  706. if (!congestion.isCongested())
  707. return false;
  708. eta = congestion.getUncongestedETA();
  709. if (eta >= 0)
  710. congestionTimer.start(eta);
  711. return true;
  712. }
  713. void VNCSConnectionST::writeFramebufferUpdate()
  714. {
  715. congestion.updatePosition(sock->outStream().length());
  716. // We're in the middle of processing a command that's supposed to be
  717. // synchronised. Allowing an update to slip out right now might violate
  718. // that synchronisation.
  719. if (syncFence)
  720. return;
  721. // We try to aggregate responses, so don't send out anything whilst we
  722. // still have incoming messages. processMessages() will give us another
  723. // chance to run once things are idle.
  724. if (inProcessMessages)
  725. return;
  726. if (state() != RFBSTATE_NORMAL)
  727. return;
  728. if (requested.is_empty() && !continuousUpdates)
  729. return;
  730. // Check that we actually have some space on the link and retry in a
  731. // bit if things are congested.
  732. if (isCongested())
  733. return;
  734. // Updates often consists of many small writes, and in continuous
  735. // mode, we will also have small fence messages around the update. We
  736. // need to aggregate these in order to not clog up TCP's congestion
  737. // window.
  738. getOutStream()->cork(true);
  739. // First take care of any updates that cannot contain framebuffer data
  740. // changes.
  741. writeNoDataUpdate();
  742. // Then real data (if possible)
  743. writeDataUpdate();
  744. getOutStream()->cork(false);
  745. congestion.updatePosition(sock->outStream().length());
  746. }
  747. void VNCSConnectionST::writeNoDataUpdate()
  748. {
  749. if (!writer()->needNoDataUpdate())
  750. return;
  751. writer()->writeNoDataUpdate();
  752. // Make sure no data update is sent until next request
  753. requested.clear();
  754. }
  755. void VNCSConnectionST::writeDataUpdate()
  756. {
  757. Region req;
  758. UpdateInfo ui;
  759. bool needNewUpdateInfo;
  760. const RenderedCursor *cursor;
  761. // See what the client has requested (if anything)
  762. if (continuousUpdates)
  763. req = cuRegion.union_(requested);
  764. else
  765. req = requested;
  766. if (req.is_empty())
  767. return;
  768. // Get the lists of updates. Prior to exporting the data to the `ui' object,
  769. // getUpdateInfo() will normalize the `updates' object such way that its
  770. // `changed' and `copied' regions would not intersect.
  771. updates.getUpdateInfo(&ui, req);
  772. needNewUpdateInfo = false;
  773. // If the previous position of the rendered cursor overlaps the source of the
  774. // copy, then when the copy happens the corresponding rectangle in the
  775. // destination will be wrong, so add it to the changed region.
  776. if (!ui.copied.is_empty() && !damagedCursorRegion.is_empty()) {
  777. Region bogusCopiedCursor;
  778. bogusCopiedCursor = damagedCursorRegion;
  779. bogusCopiedCursor.translate(ui.copy_delta);
  780. bogusCopiedCursor.assign_intersect(server->getPixelBuffer()->getRect());
  781. if (!ui.copied.intersect(bogusCopiedCursor).is_empty()) {
  782. updates.add_changed(bogusCopiedCursor);
  783. needNewUpdateInfo = true;
  784. }
  785. }
  786. // If we need to remove the old rendered cursor, just add the region to
  787. // the changed region.
  788. if (removeRenderedCursor) {
  789. updates.add_changed(damagedCursorRegion);
  790. needNewUpdateInfo = true;
  791. damagedCursorRegion.clear();
  792. removeRenderedCursor = false;
  793. }
  794. // If we need a full cursor update then make sure its entire region
  795. // is marked as changed.
  796. if (updateRenderedCursor) {
  797. updates.add_changed(server->getRenderedCursor()->getEffectiveRect());
  798. needNewUpdateInfo = true;
  799. updateRenderedCursor = false;
  800. }
  801. // The `updates' object could change, make sure we have valid update info.
  802. if (needNewUpdateInfo)
  803. updates.getUpdateInfo(&ui, req);
  804. // If there are queued updates then we cannot safely send an update
  805. // without risking a partially updated screen
  806. if (!server->getPendingRegion().is_empty()) {
  807. req.clear();
  808. ui.changed.clear();
  809. ui.copied.clear();
  810. }
  811. // Does the client need a server-side rendered cursor?
  812. cursor = NULL;
  813. if (needRenderedCursor()) {
  814. Rect renderedCursorRect;
  815. cursor = server->getRenderedCursor();
  816. renderedCursorRect = cursor->getEffectiveRect();
  817. // Check that we don't try to copy over the cursor area, and
  818. // if that happens we need to treat it as changed so that we can
  819. // re-render it
  820. if (!ui.copied.intersect(renderedCursorRect).is_empty()) {
  821. ui.changed.assign_union(ui.copied.intersect(renderedCursorRect));
  822. ui.copied.assign_subtract(renderedCursorRect);
  823. }
  824. // Track where we've rendered the cursor
  825. damagedCursorRegion.assign_union(ui.changed.intersect(renderedCursorRect));
  826. }
  827. // If we don't have a normal update, then try a lossless refresh
  828. if (ui.is_empty() && !writer()->needFakeUpdate()) {
  829. writeLosslessRefresh();
  830. return;
  831. }
  832. // We have something to send, so let's get to it
  833. writeRTTPing();
  834. encodeManager.writeUpdate(ui, server->getPixelBuffer(), cursor);
  835. writeRTTPing();
  836. // The request might be for just part of the screen, so we cannot
  837. // just clear the entire update tracker.
  838. updates.subtract(req);
  839. requested.clear();
  840. }
  841. void VNCSConnectionST::writeLosslessRefresh()
  842. {
  843. Region req, pending;
  844. const RenderedCursor *cursor;
  845. int nextRefresh, nextUpdate;
  846. size_t bandwidth, maxUpdateSize;
  847. if (continuousUpdates)
  848. req = cuRegion.union_(requested);
  849. else
  850. req = requested;
  851. // If there are queued updates then we could not safely send an
  852. // update without risking a partially updated screen, however we
  853. // might still be able to send a lossless refresh
  854. pending = server->getPendingRegion();
  855. if (!pending.is_empty()) {
  856. UpdateInfo ui;
  857. // Don't touch the updates pending in the server core
  858. req.assign_subtract(pending);
  859. // Or any updates pending just for this connection
  860. updates.getUpdateInfo(&ui, req);
  861. req.assign_subtract(ui.changed);
  862. req.assign_subtract(ui.copied);
  863. }
  864. // Any lossy area we can refresh?
  865. if (!encodeManager.needsLosslessRefresh(req))
  866. return;
  867. // Right away? Or later?
  868. nextRefresh = encodeManager.getNextLosslessRefresh(req);
  869. if (nextRefresh > 0) {
  870. losslessTimer.start(nextRefresh);
  871. return;
  872. }
  873. // Prepare the cursor in case it overlaps with a region getting
  874. // refreshed
  875. cursor = NULL;
  876. if (needRenderedCursor())
  877. cursor = server->getRenderedCursor();
  878. // FIXME: If continuous updates aren't used then the client might
  879. // be slower than frameRate in its requests and we could
  880. // afford a larger update size
  881. nextUpdate = server->msToNextUpdate();
  882. // Don't bother if we're about to send a real update
  883. if (nextUpdate == 0)
  884. return;
  885. // FIXME: Bandwidth estimation without congestion control
  886. bandwidth = congestion.getBandwidth();
  887. // FIXME: Hard coded value for maximum CPU throughput
  888. if (bandwidth > 5000000)
  889. bandwidth = 5000000;
  890. maxUpdateSize = bandwidth * nextUpdate / 1000;
  891. writeRTTPing();
  892. encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
  893. cursor, maxUpdateSize);
  894. writeRTTPing();
  895. requested.clear();
  896. }
  897. void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
  898. {
  899. if (!authenticated())
  900. return;
  901. client.setDimensions(client.width(), client.height(),
  902. server->getScreenLayout());
  903. if (state() != RFBSTATE_NORMAL)
  904. return;
  905. writer()->writeDesktopSize(reason);
  906. }
  907. // setCursor() is called whenever the cursor has changed shape or pixel format.
  908. // If the client supports local cursor then it will arrange for the cursor to
  909. // be sent to the client.
  910. void VNCSConnectionST::setCursor()
  911. {
  912. if (state() != RFBSTATE_NORMAL)
  913. return;
  914. // We need to blank out the client's cursor or there will be two
  915. if (needRenderedCursor()) {
  916. client.setCursor(emptyCursor);
  917. clientHasCursor = false;
  918. } else {
  919. client.setCursor(*server->getCursor());
  920. clientHasCursor = true;
  921. }
  922. if (client.supportsLocalCursor())
  923. writer()->writeCursor();
  924. }
  925. // setCursorPos() is called whenever the cursor has changed position by the
  926. // server. If the client supports being informed about these changes then it
  927. // will arrange for the new cursor position to be sent to the client.
  928. void VNCSConnectionST::setCursorPos()
  929. {
  930. if (state() != RFBSTATE_NORMAL)
  931. return;
  932. if (client.supportsCursorPosition()) {
  933. client.setCursorPos(server->getCursorPos());
  934. writer()->writeCursorPos();
  935. }
  936. }
  937. void VNCSConnectionST::setDesktopName(const char *name)
  938. {
  939. client.setName(name);
  940. if (state() != RFBSTATE_NORMAL)
  941. return;
  942. if (client.supportsEncoding(pseudoEncodingDesktopName))
  943. writer()->writeSetDesktopName();
  944. }
  945. void VNCSConnectionST::setLEDState(unsigned int ledstate)
  946. {
  947. if (state() != RFBSTATE_NORMAL)
  948. return;
  949. client.setLEDState(ledstate);
  950. if (client.supportsLEDState())
  951. writer()->writeLEDState();
  952. }