選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

VNCSConnectionST.cxx 31KB

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