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

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