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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2009-2018 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. #include <network/TcpSocket.h>
  20. #include <rfb/ComparingUpdateTracker.h>
  21. #include <rfb/Encoder.h>
  22. #include <rfb/KeyRemapper.h>
  23. #include <rfb/LogWriter.h>
  24. #include <rfb/Security.h>
  25. #include <rfb/ServerCore.h>
  26. #include <rfb/SMsgWriter.h>
  27. #include <rfb/VNCServerST.h>
  28. #include <rfb/VNCSConnectionST.h>
  29. #include <rfb/screenTypes.h>
  30. #include <rfb/fenceTypes.h>
  31. #include <rfb/ledStates.h>
  32. #define XK_LATIN1
  33. #define XK_MISCELLANY
  34. #define XK_XKB_KEYS
  35. #include <rfb/keysymdef.h>
  36. using namespace rfb;
  37. static LogWriter vlog("VNCSConnST");
  38. static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
  39. VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
  40. bool reverse)
  41. : sock(s), reverseConnection(reverse),
  42. inProcessMessages(false),
  43. pendingSyncFence(false), syncFence(false), fenceFlags(0),
  44. fenceDataLen(0), fenceData(NULL), congestionTimer(this),
  45. server(server_), updates(false),
  46. updateRenderedCursor(false), removeRenderedCursor(false),
  47. continuousUpdates(false), encodeManager(this), pointerEventTime(0),
  48. clientHasCursor(false),
  49. accessRights(AccessDefault), startTime(time(0))
  50. {
  51. setStreams(&sock->inStream(), &sock->outStream());
  52. peerEndpoint.buf = sock->getPeerEndpoint();
  53. VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
  54. // Configure the socket
  55. setSocketTimeouts();
  56. lastEventTime = time(0);
  57. server->clients.push_front(this);
  58. }
  59. VNCSConnectionST::~VNCSConnectionST()
  60. {
  61. // If we reach here then VNCServerST is deleting us!
  62. VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
  63. peerEndpoint.buf,
  64. (closeReason.buf) ? closeReason.buf : "");
  65. // Release any keys the client still had pressed
  66. while (!pressedKeys.empty()) {
  67. rdr::U32 keysym, keycode;
  68. keysym = pressedKeys.begin()->second;
  69. keycode = pressedKeys.begin()->first;
  70. pressedKeys.erase(pressedKeys.begin());
  71. vlog.debug("Releasing key 0x%x / 0x%x on client disconnect",
  72. keysym, keycode);
  73. server->desktop->keyEvent(keysym, keycode, false);
  74. }
  75. if (server->pointerClient == this)
  76. server->pointerClient = 0;
  77. // Remove this client from the server
  78. server->clients.remove(this);
  79. delete [] fenceData;
  80. }
  81. // Methods called from VNCServerST
  82. bool VNCSConnectionST::init()
  83. {
  84. try {
  85. initialiseProtocol();
  86. } catch (rdr::Exception& e) {
  87. close(e.str());
  88. return false;
  89. }
  90. return true;
  91. }
  92. void VNCSConnectionST::close(const char* reason)
  93. {
  94. // Log the reason for the close
  95. if (!closeReason.buf)
  96. closeReason.buf = strDup(reason);
  97. else
  98. vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
  99. if (authenticated()) {
  100. server->lastDisconnectTime = time(0);
  101. }
  102. // Just shutdown the socket and mark our state as closing. Eventually the
  103. // calling code will call VNCServerST's removeSocket() method causing us to
  104. // be deleted.
  105. sock->shutdown();
  106. setState(RFBSTATE_CLOSING);
  107. }
  108. void VNCSConnectionST::processMessages()
  109. {
  110. if (state() == RFBSTATE_CLOSING) return;
  111. try {
  112. // - Now set appropriate socket timeouts and process data
  113. setSocketTimeouts();
  114. inProcessMessages = true;
  115. // Get the underlying TCP layer to build large packets if we send
  116. // multiple small responses.
  117. sock->cork(true);
  118. while (getInStream()->checkNoWait(1)) {
  119. if (pendingSyncFence) {
  120. syncFence = true;
  121. pendingSyncFence = false;
  122. }
  123. processMsg();
  124. if (syncFence) {
  125. writer()->writeFence(fenceFlags, fenceDataLen, fenceData);
  126. syncFence = false;
  127. }
  128. }
  129. // Flush out everything in case we go idle after this.
  130. sock->cork(false);
  131. inProcessMessages = false;
  132. // If there were anything requiring an update, try to send it here.
  133. // We wait until now with this to aggregate responses and to give
  134. // higher priority to user actions such as keyboard and pointer events.
  135. writeFramebufferUpdate();
  136. } catch (rdr::EndOfStream&) {
  137. close("Clean disconnection");
  138. } catch (rdr::Exception &e) {
  139. close(e.str());
  140. }
  141. }
  142. void VNCSConnectionST::flushSocket()
  143. {
  144. if (state() == RFBSTATE_CLOSING) return;
  145. try {
  146. setSocketTimeouts();
  147. sock->outStream().flush();
  148. // Flushing the socket might release an update that was previously
  149. // delayed because of congestion.
  150. if (sock->outStream().bufferUsage() == 0)
  151. writeFramebufferUpdate();
  152. } catch (rdr::Exception &e) {
  153. close(e.str());
  154. }
  155. }
  156. void VNCSConnectionST::pixelBufferChange()
  157. {
  158. try {
  159. if (!authenticated()) return;
  160. if (cp.width && cp.height && (server->pb->width() != cp.width ||
  161. server->pb->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->pb->getRect());
  177. cp.width = server->pb->width();
  178. cp.height = server->pb->height();
  179. cp.screenLayout = server->screenLayout;
  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->pb->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->pb->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 (!(accessRights & 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->cursorPos.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. server->startDesktop();
  351. // - Set the connection parameters appropriately
  352. cp.width = server->pb->width();
  353. cp.height = server->pb->height();
  354. cp.screenLayout = server->screenLayout;
  355. cp.setName(server->getName());
  356. cp.setLEDState(server->ledState);
  357. // - Set the default pixel format
  358. cp.setPF(server->pb->getPF());
  359. char buffer[256];
  360. cp.pf().print(buffer, 256);
  361. vlog.info("Server default pixel format %s", buffer);
  362. // - Mark the entire display as "dirty"
  363. updates.add_changed(server->pb->getRect());
  364. startTime = time(0);
  365. }
  366. void VNCSConnectionST::queryConnection(const char* userName)
  367. {
  368. // - Authentication succeeded - clear from blacklist
  369. CharArray name; name.buf = sock->getPeerAddress();
  370. server->blHosts->clearBlackmark(name.buf);
  371. // - Special case to provide a more useful error message
  372. if (rfb::Server::neverShared && !rfb::Server::disconnectClients &&
  373. server->authClientCount() > 0) {
  374. approveConnection(false, "The server is already in use");
  375. return;
  376. }
  377. // - Does the client have the right to bypass the query?
  378. if (reverseConnection ||
  379. !(rfb::Server::queryConnect || sock->requiresQuery()) ||
  380. (accessRights & AccessNoQuery))
  381. {
  382. approveConnection(true);
  383. return;
  384. }
  385. // - Get the server to display an Accept/Reject dialog, if required
  386. // If a dialog is displayed, the result will be PENDING, and the
  387. // server will call approveConnection at a later time
  388. CharArray reason;
  389. VNCServerST::queryResult qr = server->queryConnection(sock, userName,
  390. &reason.buf);
  391. if (qr == VNCServerST::PENDING)
  392. return;
  393. // - If server returns ACCEPT/REJECT then pass result to SConnection
  394. approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
  395. }
  396. void VNCSConnectionST::clientInit(bool shared)
  397. {
  398. lastEventTime = time(0);
  399. if (rfb::Server::alwaysShared || reverseConnection) shared = true;
  400. if (!(accessRights & AccessNonShared)) shared = true;
  401. if (rfb::Server::neverShared) shared = false;
  402. if (!shared) {
  403. if (rfb::Server::disconnectClients && (accessRights & AccessNonShared)) {
  404. // - Close all the other connected clients
  405. vlog.debug("non-shared connection - closing clients");
  406. server->closeClients("Non-shared connection requested", getSock());
  407. } else {
  408. // - Refuse this connection if there are existing clients, in addition to
  409. // this one
  410. if (server->authClientCount() > 1) {
  411. close("Server is already in use");
  412. return;
  413. }
  414. }
  415. }
  416. SConnection::clientInit(shared);
  417. }
  418. void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
  419. {
  420. SConnection::setPixelFormat(pf);
  421. char buffer[256];
  422. pf.print(buffer, 256);
  423. vlog.info("Client pixel format %s", buffer);
  424. setCursor();
  425. }
  426. void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
  427. {
  428. pointerEventTime = lastEventTime = time(0);
  429. server->lastUserInputTime = lastEventTime;
  430. if (!(accessRights & AccessPtrEvents)) return;
  431. if (!rfb::Server::acceptPointerEvents) return;
  432. if (!server->pointerClient || server->pointerClient == this) {
  433. pointerEventPos = pos;
  434. if (buttonMask)
  435. server->pointerClient = this;
  436. else
  437. server->pointerClient = 0;
  438. server->desktop->pointerEvent(pointerEventPos, buttonMask);
  439. }
  440. }
  441. class VNCSConnectionSTShiftPresser {
  442. public:
  443. VNCSConnectionSTShiftPresser(SDesktop* desktop_)
  444. : desktop(desktop_), pressed(false) {}
  445. ~VNCSConnectionSTShiftPresser() {
  446. if (pressed) {
  447. vlog.debug("Releasing fake Shift_L");
  448. desktop->keyEvent(XK_Shift_L, 0, false);
  449. }
  450. }
  451. void press() {
  452. vlog.debug("Pressing fake Shift_L");
  453. desktop->keyEvent(XK_Shift_L, 0, true);
  454. pressed = true;
  455. }
  456. SDesktop* desktop;
  457. bool pressed;
  458. };
  459. // keyEvent() - record in the pressedKeys which keys were pressed. Allow
  460. // multiple down events (for autorepeat), but only allow a single up event.
  461. void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
  462. rdr::U32 lookup;
  463. lastEventTime = time(0);
  464. server->lastUserInputTime = lastEventTime;
  465. if (!(accessRights & AccessKeyEvents)) return;
  466. if (!rfb::Server::acceptKeyEvents) return;
  467. if (down)
  468. vlog.debug("Key pressed: 0x%x / 0x%x", keysym, keycode);
  469. else
  470. vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);
  471. // Remap the key if required
  472. if (server->keyRemapper) {
  473. rdr::U32 newkey;
  474. newkey = server->keyRemapper->remapKey(keysym);
  475. if (newkey != keysym) {
  476. vlog.debug("Key remapped to 0x%x", newkey);
  477. keysym = newkey;
  478. }
  479. }
  480. // Avoid lock keys if we don't know the server state
  481. if ((server->ledState == ledUnknown) &&
  482. ((keysym == XK_Caps_Lock) ||
  483. (keysym == XK_Num_Lock) ||
  484. (keysym == XK_Scroll_Lock))) {
  485. vlog.debug("Ignoring lock key (e.g. caps lock)");
  486. return;
  487. }
  488. // Lock key heuristics
  489. // (only for clients that do not support the LED state extension)
  490. if (!cp.supportsLEDState) {
  491. // Always ignore ScrollLock as we don't have a heuristic
  492. // for that
  493. if (keysym == XK_Scroll_Lock) {
  494. vlog.debug("Ignoring lock key (e.g. caps lock)");
  495. return;
  496. }
  497. if (down && (server->ledState != ledUnknown)) {
  498. // CapsLock synchronisation heuristic
  499. // (this assumes standard interaction between CapsLock the Shift
  500. // keys and normal characters)
  501. if (((keysym >= XK_A) && (keysym <= XK_Z)) ||
  502. ((keysym >= XK_a) && (keysym <= XK_z))) {
  503. bool uppercase, shift, lock;
  504. uppercase = (keysym >= XK_A) && (keysym <= XK_Z);
  505. shift = isShiftPressed();
  506. lock = server->ledState & ledCapsLock;
  507. if (lock == (uppercase == shift)) {
  508. vlog.debug("Inserting fake CapsLock to get in sync with client");
  509. server->desktop->keyEvent(XK_Caps_Lock, 0, true);
  510. server->desktop->keyEvent(XK_Caps_Lock, 0, false);
  511. }
  512. }
  513. // NumLock synchronisation heuristic
  514. // (this is more cautious because of the differences between Unix,
  515. // Windows and macOS)
  516. if (((keysym >= XK_KP_Home) && (keysym <= XK_KP_Delete)) ||
  517. ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  518. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal)) {
  519. bool number, shift, lock;
  520. number = ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  521. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal);
  522. shift = isShiftPressed();
  523. lock = server->ledState & ledNumLock;
  524. if (shift) {
  525. // We don't know the appropriate NumLock state for when Shift
  526. // is pressed as it could be one of:
  527. //
  528. // a) A Unix client where Shift negates NumLock
  529. //
  530. // b) A Windows client where Shift only cancels NumLock
  531. //
  532. // c) A macOS client where Shift doesn't have any effect
  533. //
  534. } else if (lock == (number == shift)) {
  535. vlog.debug("Inserting fake NumLock to get in sync with client");
  536. server->desktop->keyEvent(XK_Num_Lock, 0, true);
  537. server->desktop->keyEvent(XK_Num_Lock, 0, false);
  538. }
  539. }
  540. }
  541. }
  542. // Turn ISO_Left_Tab into shifted Tab.
  543. VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
  544. if (keysym == XK_ISO_Left_Tab) {
  545. if (!isShiftPressed())
  546. shiftPresser.press();
  547. keysym = XK_Tab;
  548. }
  549. // We need to be able to track keys, so generate a fake index when we
  550. // aren't given a keycode
  551. if (keycode == 0)
  552. lookup = 0x80000000 | keysym;
  553. else
  554. lookup = keycode;
  555. // We force the same keysym for an already down key for the
  556. // sake of sanity
  557. if (pressedKeys.find(lookup) != pressedKeys.end())
  558. keysym = pressedKeys[lookup];
  559. if (down) {
  560. pressedKeys[lookup] = keysym;
  561. } else {
  562. if (!pressedKeys.erase(lookup))
  563. return;
  564. }
  565. server->desktop->keyEvent(keysym, keycode, down);
  566. }
  567. void VNCSConnectionST::clientCutText(const char* str, int len)
  568. {
  569. if (!(accessRights & AccessCutText)) return;
  570. if (!rfb::Server::acceptCutText) return;
  571. server->desktop->clientCutText(str, len);
  572. }
  573. void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
  574. {
  575. Rect safeRect;
  576. if (!(accessRights & AccessView)) return;
  577. SConnection::framebufferUpdateRequest(r, incremental);
  578. // Check that the client isn't sending crappy requests
  579. if (!r.enclosed_by(Rect(0, 0, cp.width, cp.height))) {
  580. vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
  581. r.width(), r.height(), r.tl.x, r.tl.y, cp.width, cp.height);
  582. safeRect = r.intersect(Rect(0, 0, cp.width, cp.height));
  583. } else {
  584. safeRect = r;
  585. }
  586. // Just update the requested region.
  587. // Framebuffer update will be sent a bit later, see processMessages().
  588. Region reqRgn(r);
  589. if (!incremental || !continuousUpdates)
  590. requested.assign_union(reqRgn);
  591. if (!incremental) {
  592. // Non-incremental update - treat as if area requested has changed
  593. updates.add_changed(reqRgn);
  594. // And send the screen layout to the client (which, unlike the
  595. // framebuffer dimensions, the client doesn't get during init)
  596. writer()->writeExtendedDesktopSize();
  597. // We do not send a DesktopSize since it only contains the
  598. // framebuffer size (which the client already should know) and
  599. // because some clients don't handle extra DesktopSize events
  600. // very well.
  601. }
  602. }
  603. void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
  604. const ScreenSet& layout)
  605. {
  606. unsigned int result;
  607. if (!(accessRights & AccessSetDesktopSize)) return;
  608. if (!rfb::Server::acceptSetDesktopSize) return;
  609. // Don't bother the desktop with an invalid configuration
  610. if (!layout.validate(fb_width, fb_height)) {
  611. writer()->writeExtendedDesktopSize(reasonClient, resultInvalid,
  612. fb_width, fb_height, layout);
  613. return;
  614. }
  615. // FIXME: the desktop will call back to VNCServerST and an extra set
  616. // of ExtendedDesktopSize messages will be sent. This is okay
  617. // protocol-wise, but unnecessary.
  618. result = server->desktop->setScreenLayout(fb_width, fb_height, layout);
  619. writer()->writeExtendedDesktopSize(reasonClient, result,
  620. fb_width, fb_height, layout);
  621. // Only notify other clients on success
  622. if (result == resultSuccess) {
  623. if (server->screenLayout != layout)
  624. throw Exception("Desktop configured a different screen layout than requested");
  625. server->notifyScreenLayoutChange(this);
  626. }
  627. }
  628. void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
  629. {
  630. rdr::U8 type;
  631. if (flags & fenceFlagRequest) {
  632. if (flags & fenceFlagSyncNext) {
  633. pendingSyncFence = true;
  634. fenceFlags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter | fenceFlagSyncNext);
  635. fenceDataLen = len;
  636. delete [] fenceData;
  637. fenceData = NULL;
  638. if (len > 0) {
  639. fenceData = new char[len];
  640. memcpy(fenceData, data, len);
  641. }
  642. return;
  643. }
  644. // We handle everything synchronously so we trivially honor these modes
  645. flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter);
  646. writer()->writeFence(flags, len, data);
  647. return;
  648. }
  649. if (len < 1)
  650. vlog.error("Fence response of unexpected size received");
  651. type = data[0];
  652. switch (type) {
  653. case 0:
  654. // Initial dummy fence;
  655. break;
  656. case 1:
  657. congestion.gotPong();
  658. break;
  659. default:
  660. vlog.error("Fence response of unexpected type received");
  661. }
  662. }
  663. void VNCSConnectionST::enableContinuousUpdates(bool enable,
  664. int x, int y, int w, int h)
  665. {
  666. Rect rect;
  667. if (!cp.supportsFence || !cp.supportsContinuousUpdates)
  668. throw Exception("Client tried to enable continuous updates when not allowed");
  669. continuousUpdates = enable;
  670. rect.setXYWH(x, y, w, h);
  671. cuRegion.reset(rect);
  672. if (enable) {
  673. requested.clear();
  674. } else {
  675. writer()->writeEndOfContinuousUpdates();
  676. }
  677. }
  678. // supportsLocalCursor() is called whenever the status of
  679. // cp.supportsLocalCursor has changed. If the client does now support local
  680. // cursor, we make sure that the old server-side rendered cursor is cleaned up
  681. // and the cursor is sent to the client.
  682. void VNCSConnectionST::supportsLocalCursor()
  683. {
  684. bool hasRenderedCursor = !damagedCursorRegion.is_empty();
  685. if (hasRenderedCursor && !needRenderedCursor())
  686. removeRenderedCursor = true;
  687. setCursor();
  688. }
  689. void VNCSConnectionST::supportsFence()
  690. {
  691. char type = 0;
  692. writer()->writeFence(fenceFlagRequest, sizeof(type), &type);
  693. }
  694. void VNCSConnectionST::supportsContinuousUpdates()
  695. {
  696. // We refuse to use continuous updates if we cannot monitor the buffer
  697. // usage using fences.
  698. if (!cp.supportsFence)
  699. return;
  700. writer()->writeEndOfContinuousUpdates();
  701. }
  702. void VNCSConnectionST::supportsLEDState()
  703. {
  704. writer()->writeLEDState();
  705. }
  706. bool VNCSConnectionST::handleTimeout(Timer* t)
  707. {
  708. try {
  709. if (t == &congestionTimer)
  710. writeFramebufferUpdate();
  711. } catch (rdr::Exception& e) {
  712. close(e.str());
  713. }
  714. return false;
  715. }
  716. bool VNCSConnectionST::isShiftPressed()
  717. {
  718. std::map<rdr::U32, rdr::U32>::const_iterator iter;
  719. for (iter = pressedKeys.begin(); iter != pressedKeys.end(); ++iter) {
  720. if (iter->second == XK_Shift_L)
  721. return true;
  722. if (iter->second == XK_Shift_R)
  723. return true;
  724. }
  725. return false;
  726. }
  727. void VNCSConnectionST::writeRTTPing()
  728. {
  729. char type;
  730. if (!cp.supportsFence)
  731. return;
  732. congestion.updatePosition(sock->outStream().length());
  733. // We need to make sure any old update are already processed by the
  734. // time we get the response back. This allows us to reliably throttle
  735. // back on client overload, as well as network overload.
  736. type = 1;
  737. writer()->writeFence(fenceFlagRequest | fenceFlagBlockBefore,
  738. sizeof(type), &type);
  739. congestion.sentPing();
  740. }
  741. bool VNCSConnectionST::isCongested()
  742. {
  743. unsigned eta;
  744. congestionTimer.stop();
  745. // Stuff still waiting in the send buffer?
  746. sock->outStream().flush();
  747. congestion.debugTrace("congestion-trace.csv", sock->getFd());
  748. if (sock->outStream().bufferUsage() > 0)
  749. return true;
  750. if (!cp.supportsFence)
  751. return false;
  752. congestion.updatePosition(sock->outStream().length());
  753. if (!congestion.isCongested())
  754. return false;
  755. eta = congestion.getUncongestedETA();
  756. if (eta >= 0)
  757. congestionTimer.start(eta);
  758. return true;
  759. }
  760. void VNCSConnectionST::writeFramebufferUpdate()
  761. {
  762. congestion.updatePosition(sock->outStream().length());
  763. // We're in the middle of processing a command that's supposed to be
  764. // synchronised. Allowing an update to slip out right now might violate
  765. // that synchronisation.
  766. if (syncFence)
  767. return;
  768. // We try to aggregate responses, so don't send out anything whilst we
  769. // still have incoming messages. processMessages() will give us another
  770. // chance to run once things are idle.
  771. if (inProcessMessages)
  772. return;
  773. if (state() != RFBSTATE_NORMAL)
  774. return;
  775. if (requested.is_empty() && !continuousUpdates)
  776. return;
  777. // Check that we actually have some space on the link and retry in a
  778. // bit if things are congested.
  779. if (isCongested())
  780. return;
  781. // Updates often consists of many small writes, and in continuous
  782. // mode, we will also have small fence messages around the update. We
  783. // need to aggregate these in order to not clog up TCP's congestion
  784. // window.
  785. sock->cork(true);
  786. // First take care of any updates that cannot contain framebuffer data
  787. // changes.
  788. writeNoDataUpdate();
  789. // Then real data (if possible)
  790. writeDataUpdate();
  791. sock->cork(false);
  792. congestion.updatePosition(sock->outStream().length());
  793. }
  794. void VNCSConnectionST::writeNoDataUpdate()
  795. {
  796. if (!writer()->needNoDataUpdate())
  797. return;
  798. writer()->writeNoDataUpdate();
  799. // Make sure no data update is sent until next request
  800. requested.clear();
  801. }
  802. void VNCSConnectionST::writeDataUpdate()
  803. {
  804. Region req, pending;
  805. UpdateInfo ui;
  806. bool needNewUpdateInfo;
  807. const RenderedCursor *cursor;
  808. updates.enable_copyrect(cp.useCopyRect);
  809. // See what the client has requested (if anything)
  810. if (continuousUpdates)
  811. req = cuRegion.union_(requested);
  812. else
  813. req = requested;
  814. if (req.is_empty())
  815. return;
  816. // Get any framebuffer changes we haven't yet been informed of
  817. pending = server->getPendingRegion();
  818. // Get the lists of updates. Prior to exporting the data to the `ui' object,
  819. // getUpdateInfo() will normalize the `updates' object such way that its
  820. // `changed' and `copied' regions would not intersect.
  821. updates.getUpdateInfo(&ui, req);
  822. needNewUpdateInfo = false;
  823. // If the previous position of the rendered cursor overlaps the source of the
  824. // copy, then when the copy happens the corresponding rectangle in the
  825. // destination will be wrong, so add it to the changed region.
  826. if (!ui.copied.is_empty() && !damagedCursorRegion.is_empty()) {
  827. Region bogusCopiedCursor;
  828. bogusCopiedCursor = damagedCursorRegion;
  829. bogusCopiedCursor.translate(ui.copy_delta);
  830. bogusCopiedCursor.assign_intersect(server->pb->getRect());
  831. if (!ui.copied.intersect(bogusCopiedCursor).is_empty()) {
  832. updates.add_changed(bogusCopiedCursor);
  833. needNewUpdateInfo = true;
  834. }
  835. }
  836. // If we need to remove the old rendered cursor, just add the region to
  837. // the changed region.
  838. if (removeRenderedCursor) {
  839. updates.add_changed(damagedCursorRegion);
  840. needNewUpdateInfo = true;
  841. damagedCursorRegion.clear();
  842. removeRenderedCursor = false;
  843. }
  844. // If we need a full cursor update then make sure its entire region
  845. // is marked as changed.
  846. if (updateRenderedCursor) {
  847. updates.add_changed(server->getRenderedCursor()->getEffectiveRect());
  848. needNewUpdateInfo = true;
  849. updateRenderedCursor = false;
  850. }
  851. // The `updates' object could change, make sure we have valid update info.
  852. if (needNewUpdateInfo)
  853. updates.getUpdateInfo(&ui, req);
  854. // If there are queued updates then we cannot safely send an update
  855. // without risking a partially updated screen
  856. if (!pending.is_empty()) {
  857. // However we might still be able to send a lossless refresh
  858. req.assign_subtract(pending);
  859. req.assign_subtract(ui.changed);
  860. req.assign_subtract(ui.copied);
  861. ui.changed.clear();
  862. ui.copied.clear();
  863. }
  864. // Does the client need a server-side rendered cursor?
  865. cursor = NULL;
  866. if (needRenderedCursor()) {
  867. Rect renderedCursorRect;
  868. cursor = server->getRenderedCursor();
  869. renderedCursorRect = cursor->getEffectiveRect();
  870. // Check that we don't try to copy over the cursor area, and
  871. // if that happens we need to treat it as changed so that we can
  872. // re-render it
  873. if (!ui.copied.intersect(renderedCursorRect).is_empty()) {
  874. ui.changed.assign_union(ui.copied.intersect(renderedCursorRect));
  875. ui.copied.assign_subtract(renderedCursorRect);
  876. }
  877. // Track where we've rendered the cursor
  878. damagedCursorRegion.assign_union(ui.changed.intersect(renderedCursorRect));
  879. }
  880. // Return if there is nothing to send the client.
  881. if (ui.is_empty() && !writer()->needFakeUpdate() &&
  882. !encodeManager.needsLosslessRefresh(req))
  883. return;
  884. writeRTTPing();
  885. if (!ui.is_empty())
  886. encodeManager.writeUpdate(ui, server->getPixelBuffer(), cursor);
  887. else {
  888. size_t maxUpdateSize;
  889. // FIXME: If continuous updates aren't used then the client might
  890. // be slower than frameRate in its requests and we could
  891. // afford a larger update size
  892. // FIXME: Bandwidth estimation without congestion control
  893. maxUpdateSize = congestion.getBandwidth() *
  894. server->msToNextUpdate() / 1000;
  895. encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
  896. cursor, maxUpdateSize);
  897. }
  898. writeRTTPing();
  899. // The request might be for just part of the screen, so we cannot
  900. // just clear the entire update tracker.
  901. updates.subtract(req);
  902. requested.clear();
  903. }
  904. void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
  905. {
  906. if (!authenticated())
  907. return;
  908. cp.screenLayout = server->screenLayout;
  909. if (state() != RFBSTATE_NORMAL)
  910. return;
  911. writer()->writeExtendedDesktopSize(reason, 0, cp.width, cp.height,
  912. cp.screenLayout);
  913. }
  914. // setCursor() is called whenever the cursor has changed shape or pixel format.
  915. // If the client supports local cursor then it will arrange for the cursor to
  916. // be sent to the client.
  917. void VNCSConnectionST::setCursor()
  918. {
  919. if (state() != RFBSTATE_NORMAL)
  920. return;
  921. // We need to blank out the client's cursor or there will be two
  922. if (needRenderedCursor()) {
  923. cp.setCursor(emptyCursor);
  924. clientHasCursor = false;
  925. } else {
  926. cp.setCursor(*server->cursor);
  927. clientHasCursor = true;
  928. }
  929. if (!writer()->writeSetCursorWithAlpha()) {
  930. if (!writer()->writeSetCursor()) {
  931. if (!writer()->writeSetXCursor()) {
  932. // No client support
  933. return;
  934. }
  935. }
  936. }
  937. }
  938. void VNCSConnectionST::setDesktopName(const char *name)
  939. {
  940. cp.setName(name);
  941. if (state() != RFBSTATE_NORMAL)
  942. return;
  943. if (!writer()->writeSetDesktopName()) {
  944. fprintf(stderr, "Client does not support desktop rename\n");
  945. return;
  946. }
  947. }
  948. void VNCSConnectionST::setLEDState(unsigned int ledstate)
  949. {
  950. if (state() != RFBSTATE_NORMAL)
  951. return;
  952. cp.setLEDState(ledstate);
  953. writer()->writeLEDState();
  954. }
  955. void VNCSConnectionST::setSocketTimeouts()
  956. {
  957. int timeoutms = rfb::Server::clientWaitTimeMillis;
  958. soonestTimeout(&timeoutms, secsToMillis(rfb::Server::idleTimeout));
  959. if (timeoutms == 0)
  960. timeoutms = -1;
  961. sock->inStream().setTimeout(timeoutms);
  962. sock->outStream().setTimeout(timeoutms);
  963. }
  964. char* VNCSConnectionST::getStartTime()
  965. {
  966. char* result = ctime(&startTime);
  967. result[24] = '\0';
  968. return result;
  969. }
  970. void VNCSConnectionST::setStatus(int status)
  971. {
  972. switch (status) {
  973. case 0:
  974. accessRights = accessRights | AccessPtrEvents | AccessKeyEvents | AccessView;
  975. break;
  976. case 1:
  977. accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents)) | AccessView;
  978. break;
  979. case 2:
  980. accessRights = accessRights & ~(AccessPtrEvents | AccessKeyEvents | AccessView);
  981. break;
  982. }
  983. framebufferUpdateRequest(server->pb->getRect(), false);
  984. }
  985. int VNCSConnectionST::getStatus()
  986. {
  987. if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0007)
  988. return 0;
  989. if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0001)
  990. return 1;
  991. if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0000)
  992. return 2;
  993. return 4;
  994. }