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

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